mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-09-11 19:05:11 +08:00
✨ Sync 2026-08-07 10:27:26
This commit is contained in:
+1
-1
@@ -2,7 +2,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=gecoosac
|
||||
PKG_VERSION:=2.2.20251015
|
||||
PKG_RELEASE:=15
|
||||
PKG_RELEASE:=16
|
||||
|
||||
PKG_MAINTAINER:=Roc Lai <laipeng668@qq.com>
|
||||
PKG_LICENSE:=AGPL-3.0-only
|
||||
|
||||
@@ -332,8 +332,6 @@ generate_default_cert() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
mkdir -p /etc/gecoosac/tls
|
||||
|
||||
cert_cn="${cert_ip:-$cert_host}"
|
||||
cert_san="DNS:$cert_host"
|
||||
[ -n "$cert_ip" ] && cert_san="${cert_san},IP:${cert_ip}"
|
||||
@@ -371,6 +369,8 @@ generate_default_cert() {
|
||||
}
|
||||
|
||||
normalize_conf() {
|
||||
[ "$isonlyoneprot" = "0" ] || isonlyoneprot="1"
|
||||
[ "$https" = "1" ] || https="0"
|
||||
if is_safe_upload_dir "$upload_dir"; then
|
||||
upload_dir="$(normalize_path "$upload_dir")"
|
||||
else
|
||||
@@ -383,14 +383,16 @@ normalize_conf() {
|
||||
logger -t gecoosac "refusing unsupported database directory: $db_dir"
|
||||
return 1
|
||||
fi
|
||||
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 [ "$isonlyoneprot" = "0" ] && [ "$https" = "1" ]; then
|
||||
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
|
||||
}
|
||||
fi
|
||||
if is_safe_pid_dir "$piddir" "$upload_dir"; then
|
||||
piddir="$(normalize_path "$piddir")"
|
||||
else
|
||||
@@ -401,14 +403,14 @@ normalize_conf() {
|
||||
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
|
||||
}
|
||||
if [ "$isonlyoneprot" = "0" ]; then
|
||||
is_port "$m_port" || {
|
||||
logger -t gecoosac "refusing invalid management port: $m_port"
|
||||
return 1
|
||||
}
|
||||
fi
|
||||
|
||||
[ "$enabled" = "1" ] || enabled="0"
|
||||
[ "$isonlyoneprot" = "0" ] || isonlyoneprot="1"
|
||||
[ "$https" = "1" ] || https="0"
|
||||
case "$lang" in
|
||||
zh|en) ;;
|
||||
*) lang="$DEFAULT_LANG" ;;
|
||||
@@ -419,22 +421,17 @@ normalize_conf() {
|
||||
}
|
||||
|
||||
ensure_dirs() {
|
||||
local path
|
||||
|
||||
path="$(normalize_path "$upload_dir")" || return 1
|
||||
if ! ensure_dir_tree "$path" || ! mkdir -p "$db_dir" "$piddir" /etc/gecoosac/tls; then
|
||||
if ! ensure_managed_dir upload "$upload_dir" || \
|
||||
! ensure_managed_dir db "$db_dir" || \
|
||||
! ensure_managed_dir pid "$piddir" || \
|
||||
! ensure_managed_dir tls /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
|
||||
ensure_secure_dir_tree() {
|
||||
local path current part rest mode
|
||||
|
||||
path="$(normalize_path "$1")" || return 1
|
||||
current="/"
|
||||
@@ -451,11 +448,53 @@ ensure_dir_tree() {
|
||||
if [ -e "$current" ]; then
|
||||
[ -d "$current" ] || return 1
|
||||
else
|
||||
mkdir "$current" || return 1
|
||||
mode=0755
|
||||
[ -n "$rest" ] || mode=0750
|
||||
mkdir -m "$mode" "$current" || return 1
|
||||
fi
|
||||
case "$current" in
|
||||
/tmp) is_secure_dir "$current" 1 || return 1 ;;
|
||||
*) is_secure_dir "$current" || return 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
managed_dir_path() {
|
||||
local role="$1" path="$2" anchor
|
||||
|
||||
case "$role:$path" in
|
||||
db:/var/lib/gecoosac|db:/var/lib/gecoosac/*)
|
||||
anchor="$(readlink -f /var 2>/dev/null)" || return 1
|
||||
case "$anchor" in
|
||||
/var|/tmp) printf '%s%s\n' "$anchor" "${path#/var}" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
;;
|
||||
pid:/var/run|pid:/var/run/*)
|
||||
anchor="$(readlink -f /var/run 2>/dev/null)" || return 1
|
||||
[ "$anchor" = "/tmp/run" ] || return 1
|
||||
printf '%s%s\n' "$anchor" "${path#/var/run}"
|
||||
;;
|
||||
*) printf '%s\n' "$path" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
ensure_managed_dir() {
|
||||
local role="$1" path physical
|
||||
|
||||
path="$(normalize_path "$2")" || return 1
|
||||
case "$role" in
|
||||
upload) is_safe_upload_dir "$path" || return 1 ;;
|
||||
db) is_safe_db_dir "$path" "$upload_dir" || return 1 ;;
|
||||
pid) is_safe_pid_dir "$path" "$upload_dir" || return 1 ;;
|
||||
tls) [ "$path" = "/etc/gecoosac/tls" ] || return 1 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
physical="$(managed_dir_path "$role" "$path")" || return 1
|
||||
ensure_secure_dir_tree "$physical" || return 1
|
||||
[ -d "$path" ]
|
||||
}
|
||||
|
||||
prepare_service() {
|
||||
init_conf
|
||||
[ "$enabled" = "1" ] || return 0
|
||||
@@ -528,16 +567,16 @@ wait_service_stopped() {
|
||||
local i
|
||||
|
||||
if ! type service_running >/dev/null 2>&1; then
|
||||
return 0
|
||||
return 1
|
||||
fi
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 5 ]; do
|
||||
service_running gecoosac || return 0
|
||||
while service_running gecoosac; do
|
||||
[ "$i" -ge 5 ] && return 1
|
||||
sleep 1
|
||||
i=$((i + 1))
|
||||
done
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
|
||||
@@ -125,15 +125,14 @@ normalize_upload_dir() {
|
||||
|
||||
upload_dir="$(uci -q get gecoosac.config.upload_dir)"
|
||||
[ -n "$upload_dir" ] || return 0
|
||||
|
||||
if is_safe_upload_dir "$upload_dir"; then
|
||||
normalized="$(normalize_path "$upload_dir")"
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
normalized="$(normalize_path "$upload_dir")" || return 0
|
||||
case "$normalized" in
|
||||
/etc/gecoosac/upload) normalized="$DEFAULT_UPLOAD_DIR" ;;
|
||||
*) is_safe_upload_dir "$normalized" || return 0 ;;
|
||||
esac
|
||||
|
||||
[ "$upload_dir" = "$normalized" ] && return 0
|
||||
uci -q set "gecoosac.config.upload_dir=${normalized}"
|
||||
uci -q set "gecoosac.config.upload_dir=${normalized}" || return 1
|
||||
changed=1
|
||||
}
|
||||
|
||||
@@ -158,73 +157,90 @@ normalize_dir_option() {
|
||||
changed=1
|
||||
}
|
||||
|
||||
is_managed_cert_path() {
|
||||
case "$1" in
|
||||
""|"$2"|"$3") return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
is_regular_file_or_absent() {
|
||||
[ ! -e "$1" ] && [ ! -L "$1" ] && return 0
|
||||
[ -f "$1" ] && [ ! -L "$1" ]
|
||||
}
|
||||
|
||||
migrate_legacy_cert_paths() {
|
||||
local crt_file key_file migrate
|
||||
local crt_file key_file old_crt old_key new_crt new_key path
|
||||
|
||||
crt_file="$(uci -q get gecoosac.config.crt_file)"
|
||||
key_file="$(uci -q get gecoosac.config.key_file)"
|
||||
migrate=0
|
||||
is_managed_cert_path "$crt_file" "$OLD_CRT_FILE" "$DEFAULT_CRT_FILE" || return 0
|
||||
is_managed_cert_path "$key_file" "$OLD_KEY_FILE" "$DEFAULT_KEY_FILE" || return 0
|
||||
|
||||
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"
|
||||
for path in "$OLD_CRT_FILE" "$OLD_KEY_FILE" "$DEFAULT_CRT_FILE" "$DEFAULT_KEY_FILE"; do
|
||||
is_regular_file_or_absent "$path" || {
|
||||
logger -t gecoosac "refusing unsafe certificate migration path: $path"
|
||||
return 1
|
||||
}
|
||||
done
|
||||
|
||||
old_crt=0
|
||||
old_key=0
|
||||
new_crt=0
|
||||
new_key=0
|
||||
[ -f "$OLD_CRT_FILE" ] && old_crt=1
|
||||
[ -f "$OLD_KEY_FILE" ] && old_key=1
|
||||
[ -f "$DEFAULT_CRT_FILE" ] && new_crt=1
|
||||
[ -f "$DEFAULT_KEY_FILE" ] && new_key=1
|
||||
|
||||
if { [ "$old_crt" = "1" ] && [ "$new_crt" = "1" ]; } || \
|
||||
{ [ "$old_key" = "1" ] && [ "$new_key" = "1" ]; }; then
|
||||
logger -t gecoosac "refusing conflicting legacy and current certificate files"
|
||||
return 1
|
||||
fi
|
||||
if [ "$old_crt" = "1" ] && [ "$new_key" = "1" ]; then
|
||||
logger -t gecoosac "refusing reverse-split certificate migration state"
|
||||
return 1
|
||||
fi
|
||||
if [ $((old_crt + new_crt)) -ne $((old_key + new_key)) ]; then
|
||||
logger -t gecoosac "refusing incomplete certificate migration state"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$old_crt" = "1" ]; then
|
||||
mv "$OLD_CRT_FILE" "$DEFAULT_CRT_FILE" || return 1
|
||||
fi
|
||||
if [ "$old_key" = "1" ]; then
|
||||
mv "$OLD_KEY_FILE" "$DEFAULT_KEY_FILE" || return 1
|
||||
fi
|
||||
if [ -f "$DEFAULT_CRT_FILE" ]; then
|
||||
chmod 644 "$DEFAULT_CRT_FILE" || return 1
|
||||
chmod 600 "$DEFAULT_KEY_FILE" || return 1
|
||||
fi
|
||||
|
||||
if [ "$crt_file" != "$DEFAULT_CRT_FILE" ]; then
|
||||
uci -q set "gecoosac.config.crt_file=${DEFAULT_CRT_FILE}" || return 1
|
||||
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
|
||||
if [ "$key_file" != "$DEFAULT_KEY_FILE" ]; then
|
||||
uci -q set "gecoosac.config.key_file=${DEFAULT_KEY_FILE}" || return 1
|
||||
changed=1
|
||||
fi
|
||||
|
||||
[ "$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
|
||||
|
||||
migrate_legacy_cert_paths || return 1
|
||||
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_config || exit 1
|
||||
normalize_upload_dir
|
||||
normalize_upload_dir || exit 1
|
||||
normalize_dir_option db_dir "$DEFAULT_DB_DIR" is_safe_db_dir
|
||||
normalize_dir_option piddir "$DEFAULT_PID_DIR" is_safe_pid_dir
|
||||
set_default enabled 0
|
||||
@@ -243,6 +259,8 @@ set_default debug 0
|
||||
set_default showtip 0
|
||||
set_default log 0
|
||||
|
||||
[ "$changed" = "1" ] && uci -q commit gecoosac
|
||||
if [ "$changed" = "1" ]; then
|
||||
uci -q commit gecoosac || exit 1
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ include $(TOPDIR)/rules.mk
|
||||
PKG_ARCH_ghttpd:=$(ARCH)
|
||||
|
||||
PKG_NAME:=ghttpd
|
||||
PKG_VERSION:=0.0.1
|
||||
PKG_RELEASE:=3
|
||||
PKG_VERSION:=0.0.2
|
||||
PKG_RELEASE:=4
|
||||
PKG_SOURCE:=$(PKG_NAME)-binary-$(PKG_VERSION).tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/Carseason/openwrt-packages/releases/download/prebuilt/
|
||||
PKG_HASH:=skip
|
||||
|
||||
@@ -16,6 +16,13 @@ stop_default_httpd_services() {
|
||||
done
|
||||
}
|
||||
|
||||
start_default_httpd_services() {
|
||||
for service in uhttpd nginx; do
|
||||
[ -x "/etc/init.d/$service" ] || continue
|
||||
"/etc/init.d/$service" enabled && "/etc/init.d/$service" start
|
||||
done
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load ghttpd
|
||||
config_foreach get_config ghttpd
|
||||
@@ -31,6 +38,17 @@ start_service() {
|
||||
procd_close_instance
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
procd_kill "$NAME"
|
||||
config_load ghttpd
|
||||
config_foreach get_config ghttpd
|
||||
start_default_httpd_services
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "ghttpd"
|
||||
}
|
||||
|
||||
reload_service() {
|
||||
restart
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-daede
|
||||
PKG_VERSION:=1.14.7
|
||||
PKG_RELEASE:=37
|
||||
PKG_RELEASE:=38
|
||||
PKG_MAINTAINER:=kenzok8
|
||||
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
@@ -56,17 +56,17 @@ fi
|
||||
if [ -n "$ver" ]; then
|
||||
constraint="$PKG=$ver"
|
||||
else
|
||||
constraint="$PKG"
|
||||
echo "result: 软件源中没有找到 $PKG,请检查网络或软件源配置"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--- apk add -s $constraint ---"
|
||||
if apk add -s "$constraint" 2>&1; then
|
||||
echo "--- apk add $constraint ---"
|
||||
apk add "$constraint" 2>&1
|
||||
else
|
||||
echo "result: apk cannot resolve $constraint; no packages were changed"
|
||||
exit 1
|
||||
if ! apk add -s "$constraint" 2>&1; then
|
||||
echo "note: apk 预检失败,通常是系统上其它软件包的问题,继续尝试升级"
|
||||
fi
|
||||
echo "--- apk add $constraint ---"
|
||||
apk add "$constraint" 2>&1
|
||||
exit 0
|
||||
) 9>/tmp/luci-app-daede.apk.lock
|
||||
rc=$?
|
||||
if [ "$rc" != 0 ]; then
|
||||
|
||||
@@ -7,10 +7,11 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-gecoosac
|
||||
PKG_VERSION:=2.2
|
||||
PKG_RELEASE:=15
|
||||
PKG_RELEASE:=16
|
||||
|
||||
LUCI_TITLE:=LuCI Support for gecoosac
|
||||
LUCI_DEPENDS:=+luci-base +gecoosac
|
||||
LUCI_EXTRA_DEPENDS:=gecoosac (>=2.2.20251015-r5)
|
||||
LUCI_PKGARCH:=all
|
||||
PKG_LICENSE:=AGPL-3.0-only
|
||||
|
||||
|
||||
@@ -42,11 +42,16 @@ function validPortValue(value) {
|
||||
return /^[0-9]+$/.test(text) && Number.isSafeInteger(port) && port >= 1 && port <= 65535;
|
||||
}
|
||||
|
||||
function validatePortValue(section_id, value, otherOption, singlePortOption) {
|
||||
|
||||
function validatePortValue(section_id, value, otherOption, singlePortOption, activeInSinglePort) {
|
||||
const singlePort = singlePortOption.formvalue(section_id);
|
||||
|
||||
if (!activeInSinglePort && singlePort !== '0')
|
||||
return true;
|
||||
|
||||
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))
|
||||
@@ -55,6 +60,25 @@ function validatePortValue(section_id, value, otherOption, singlePortOption) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function validateCertificatePath(section_id, value, singlePortOption, httpsOption) {
|
||||
if (singlePortOption.formvalue(section_id) !== '0' || httpsOption.formvalue(section_id) !== '1' || !value)
|
||||
return true;
|
||||
|
||||
return String(value).charAt(0) === '/' ? true : _('Expecting an absolute path');
|
||||
}
|
||||
|
||||
function triggerActiveValidation(section_id, options) {
|
||||
for (const option of options) {
|
||||
if (!option.isActive(section_id))
|
||||
continue;
|
||||
|
||||
const element = option.getUIElement(section_id);
|
||||
|
||||
if (element)
|
||||
element.triggerValidation();
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePath(value) {
|
||||
const path = String(value || '');
|
||||
|
||||
@@ -217,6 +241,7 @@ return view.extend({
|
||||
render(data) {
|
||||
let m, s, o, uploadDirOption;
|
||||
let portOption, managementPortOption, singlePortOption;
|
||||
let httpsOption, certificateOption, keyOption;
|
||||
|
||||
m = new form.Map('gecoosac', _('Gecoos AC'),
|
||||
_('Only supports Gecoos AP firmware 7.6 and above.') + '<br />' +
|
||||
@@ -272,10 +297,10 @@ return view.extend({
|
||||
o.depends('isonlyoneprot', '0');
|
||||
|
||||
portOption.validate = function(section_id, value) {
|
||||
return validatePortValue(section_id, value, managementPortOption, singlePortOption);
|
||||
return validatePortValue(section_id, value, managementPortOption, singlePortOption, true);
|
||||
};
|
||||
managementPortOption.validate = function(section_id, value) {
|
||||
return validatePortValue(section_id, value, portOption, singlePortOption);
|
||||
return validatePortValue(section_id, value, portOption, singlePortOption, false);
|
||||
};
|
||||
singlePortOption.validate = function(section_id, value) {
|
||||
if (value === '0') {
|
||||
@@ -288,34 +313,46 @@ return view.extend({
|
||||
|
||||
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'),
|
||||
httpsOption = 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 = httpsOption;
|
||||
o.default = '0';
|
||||
o.depends('isonlyoneprot', '0');
|
||||
|
||||
o = s.option(form.Value, 'crt_file', _('Specify crt certificate file'));
|
||||
certificateOption = s.option(form.Value, 'crt_file', _('Specify crt certificate file'));
|
||||
o = certificateOption;
|
||||
o.placeholder = DEFAULT_CRT_FILE;
|
||||
o.default = DEFAULT_CRT_FILE;
|
||||
o.datatype = 'file';
|
||||
o.depends({ isonlyoneprot: '0', https: '1' });
|
||||
o.validate = function(section_id, value) {
|
||||
return validateCertificatePath(section_id, value, singlePortOption, httpsOption);
|
||||
};
|
||||
|
||||
o = s.option(form.Value, 'key_file', _('Specify key certificate file'));
|
||||
keyOption = s.option(form.Value, 'key_file', _('Specify key certificate file'));
|
||||
o = keyOption;
|
||||
o.placeholder = DEFAULT_KEY_FILE;
|
||||
o.default = DEFAULT_KEY_FILE;
|
||||
o.datatype = 'file';
|
||||
o.depends({ isonlyoneprot: '0', https: '1' });
|
||||
o.validate = function(section_id, value) {
|
||||
return validateCertificatePath(section_id, value, singlePortOption, httpsOption);
|
||||
};
|
||||
|
||||
const revalidateProtocolOptions = function(_event, section_id) {
|
||||
triggerActiveValidation(section_id, [
|
||||
portOption,
|
||||
managementPortOption,
|
||||
singlePortOption,
|
||||
httpsOption,
|
||||
certificateOption,
|
||||
keyOption
|
||||
]);
|
||||
};
|
||||
portOption.onchange = revalidateProtocolOptions;
|
||||
managementPortOption.onchange = revalidateProtocolOptions;
|
||||
singlePortOption.onchange = revalidateProtocolOptions;
|
||||
httpsOption.onchange = revalidateProtocolOptions;
|
||||
|
||||
o = s.option(form.Value, 'upload_dir', _('Upload dir path'),
|
||||
_('Upload AP upgrade firmware here. Use an absolute path ending with /gecoosac/upload, for example /tmp/gecoosac/upload.<br />Do not place it under /etc/gecoosac because that directory is backed up during sysupgrade.'));
|
||||
|
||||
@@ -132,6 +132,7 @@ configured_path_in_upload() {
|
||||
|
||||
path="$(normalize_path "$path")" || return 2
|
||||
path_in_dir "$path" "$upload_path" && return 0
|
||||
[ -e "$path" ] || [ -L "$path" ] || return 1
|
||||
|
||||
real_path="$(readlink -f "$path" 2>/dev/null)" || return 2
|
||||
[ -n "$real_path" ] || return 2
|
||||
@@ -165,29 +166,74 @@ service_status() {
|
||||
}
|
||||
|
||||
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
|
||||
if json_select instances 2>/dev/null; then
|
||||
json_get_keys instances
|
||||
for instance in $instances; do
|
||||
json_select "$instance" 2>/dev/null || continue
|
||||
json_get_var state running
|
||||
json_select ..
|
||||
if [ "$state" = "1" ]; then
|
||||
running=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
json_get_keys instances
|
||||
for instance in $instances; do
|
||||
json_select "$instance" 2>/dev/null || continue
|
||||
json_get_var state running
|
||||
json_select ..
|
||||
if [ "$state" = "1" ]; then
|
||||
running=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
json_cleanup
|
||||
status_result 1 "$running"
|
||||
}
|
||||
|
||||
clear_upload_unlock() {
|
||||
flock -u 9 >/dev/null 2>&1
|
||||
exec 9<&-
|
||||
}
|
||||
|
||||
clear_upload_locked_result() {
|
||||
clear_upload_unlock
|
||||
json_result "$1" "$2" "$3"
|
||||
}
|
||||
|
||||
is_safe_clear_stage() {
|
||||
local stage="$1"
|
||||
|
||||
[ -d "$stage" ] && [ ! -L "$stage" ] || return 1
|
||||
is_secure_dir "$stage" || return 1
|
||||
if [ -e "$stage/upload" ] || [ -L "$stage/upload" ]; then
|
||||
[ -d "$stage/upload" ] && [ ! -L "$stage/upload" ] || return 1
|
||||
is_secure_upload_dir "$stage/upload" || return 1
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_live_upload_dir() {
|
||||
local path="$1"
|
||||
|
||||
if [ ! -e "$path" ] && [ ! -L "$path" ]; then
|
||||
mkdir "$path" 2>/dev/null || {
|
||||
[ -d "$path" ] && [ ! -L "$path" ] || return 1
|
||||
}
|
||||
fi
|
||||
[ -d "$path" ] && [ ! -L "$path" ] || return 1
|
||||
chmod 0750 "$path" || return 1
|
||||
is_secure_upload_dir "$path"
|
||||
}
|
||||
|
||||
validate_clear_protected_paths() {
|
||||
local root="$1" option
|
||||
|
||||
for option in db_dir piddir crt_file key_file; do
|
||||
configured_path_in_upload "$option" "$root"
|
||||
case "$?" in
|
||||
0) return 0 ;;
|
||||
1) ;;
|
||||
*) return 2 ;;
|
||||
esac
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
clear_upload() {
|
||||
local path real parent stage option
|
||||
local path real parent stage option candidate stages live_exists
|
||||
|
||||
path="$(uci -q get gecoosac.config.upload_dir)"
|
||||
[ -n "$path" ] || path="$DEFAULT_UPLOAD_DIR"
|
||||
@@ -198,70 +244,137 @@ clear_upload() {
|
||||
esac
|
||||
|
||||
path="$(normalize_path "$path")" || { json_result 0 "Expecting an absolute path"; return; }
|
||||
real="$(readlink -f "$path" 2>/dev/null)"
|
||||
if ! safe_upload_path "$path"; then
|
||||
json_result 0 "Only Gecoos upload directories can be cleared" "$path"
|
||||
return
|
||||
fi
|
||||
|
||||
parent="${path%/*}"
|
||||
if [ ! -e "$parent" ] && [ ! -L "$parent" ]; then
|
||||
json_result 1 "" "$path"
|
||||
return
|
||||
fi
|
||||
if ! is_secure_upload_dir "$parent"; then
|
||||
json_result 0 "Upload directory or its parent is not root-owned and private" "$path"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -e "$path" ] || [ -L "$path" ]; then
|
||||
real="$(readlink -f "$path" 2>/dev/null)"
|
||||
else
|
||||
real="$path"
|
||||
fi
|
||||
[ -n "$real" ] || { json_result 0 "Unable to resolve upload directory" "$path"; return; }
|
||||
real="$(normalize_path "$real")" || { json_result 0 "Expecting an absolute path"; return; }
|
||||
[ "$real" = "$path" ] || { json_result 0 "Only Gecoos upload directories can be cleared" "$real"; return; }
|
||||
|
||||
if [ "$real" != "$path" ] || ! safe_upload_path "$real"; then
|
||||
json_result 0 "Only Gecoos upload directories can be cleared" "$real"
|
||||
return
|
||||
fi
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
parent="${real%/*}"
|
||||
stage="$(mktemp -d "$parent/.gecoosac-clear.XXXXXX" 2>/dev/null)" || {
|
||||
exec 9<"$parent" 2>/dev/null || {
|
||||
json_result 0 "Unable to prepare upload directory cleanup" "$real"
|
||||
return
|
||||
}
|
||||
if ! chmod 0700 "$stage"; then
|
||||
rm -rf "$stage"
|
||||
if ! flock -n 9 >/dev/null 2>&1; then
|
||||
clear_upload_unlock
|
||||
json_result 0 "Unable to prepare upload directory cleanup" "$real"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! mv "$real" "$stage/upload"; then
|
||||
rm -rf "$stage"
|
||||
json_result 0 "Unable to prepare upload directory cleanup" "$real"
|
||||
if ! is_secure_upload_dir "$parent"; then
|
||||
clear_upload_locked_result 0 "Upload directory or its parent is not root-owned and private" "$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
|
||||
parent="${real%/*}"
|
||||
stages=0
|
||||
for candidate in "$parent"/.gecoosac-clear.??????; do
|
||||
[ "$candidate" != "$parent/.gecoosac-clear.??????" ] || continue
|
||||
stages=1
|
||||
is_safe_clear_stage "$candidate" || {
|
||||
clear_upload_locked_result 0 "Unable to validate upload cleanup stage" "$candidate"
|
||||
return
|
||||
}
|
||||
if [ -e "$candidate/upload" ] || [ -L "$candidate/upload" ]; then
|
||||
validate_clear_protected_paths "$candidate/upload"
|
||||
case "$?" in
|
||||
0) clear_upload_locked_result 0 "Upload cleanup stage contains a configured protected path" "$candidate"; return ;;
|
||||
1) ;;
|
||||
*) clear_upload_locked_result 0 "Unable to validate configured paths" "$candidate"; return ;;
|
||||
esac
|
||||
fi
|
||||
logger -t gecoosac "upload cleanup retained staged data at $stage"
|
||||
json_result 0 "Unable to remove upload directory contents" "$real"
|
||||
done
|
||||
|
||||
live_exists=0
|
||||
[ -e "$real" ] || [ -L "$real" ] && live_exists=1
|
||||
if [ "$live_exists" = "1" ] && ! is_secure_upload_dir "$real"; then
|
||||
clear_upload_locked_result 0 "Upload directory or its parent is not root-owned and private" "$real"
|
||||
return
|
||||
fi
|
||||
if [ "$live_exists" = "0" ] && [ "$stages" = "0" ]; then
|
||||
clear_upload_locked_result 1 "" "$real"
|
||||
return
|
||||
fi
|
||||
if [ "$live_exists" = "1" ]; then
|
||||
validate_clear_protected_paths "$real"
|
||||
case "$?" in
|
||||
0) clear_upload_locked_result 0 "Upload directory contains a configured protected path" "$real"; return ;;
|
||||
1) ;;
|
||||
*) clear_upload_locked_result 0 "Unable to validate configured paths" "$real"; return ;;
|
||||
esac
|
||||
fi
|
||||
if [ "$live_exists" = "0" ]; then
|
||||
ensure_live_upload_dir "$real" || {
|
||||
clear_upload_locked_result 0 "Unable to recreate upload directory" "$real"
|
||||
return
|
||||
}
|
||||
fi
|
||||
|
||||
if [ ! -d "$real" ]; then
|
||||
if ! mkdir "$real" && { [ ! -d "$real" ] || [ -L "$real" ]; }; then
|
||||
json_result 0 "Unable to recreate upload directory" "$real"
|
||||
for candidate in "$parent"/.gecoosac-clear.??????; do
|
||||
[ "$candidate" != "$parent/.gecoosac-clear.??????" ] || continue
|
||||
if [ -e "$candidate/upload" ] || [ -L "$candidate/upload" ]; then
|
||||
rm -rf "$candidate/upload" || {
|
||||
logger -t gecoosac "upload cleanup retained staged data at $candidate"
|
||||
clear_upload_locked_result 0 "Unable to remove upload directory contents" "$real"
|
||||
return
|
||||
}
|
||||
fi
|
||||
rmdir "$candidate" || {
|
||||
clear_upload_locked_result 0 "Unable to remove upload cleanup stage" "$candidate"
|
||||
return
|
||||
}
|
||||
done
|
||||
|
||||
if [ "$live_exists" = "1" ]; then
|
||||
stage="$(mktemp -d "$parent/.gecoosac-clear.XXXXXX" 2>/dev/null)" || {
|
||||
clear_upload_locked_result 0 "Unable to prepare upload directory cleanup" "$real"
|
||||
return
|
||||
}
|
||||
if ! chmod 0700 "$stage" || ! mv "$real" "$stage/upload"; then
|
||||
rm -rf "$stage"
|
||||
clear_upload_locked_result 0 "Unable to prepare upload directory cleanup" "$real"
|
||||
return
|
||||
fi
|
||||
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
|
||||
if ! ensure_live_upload_dir "$real"; then
|
||||
if [ ! -e "$real" ] && [ ! -L "$real" ]; then
|
||||
mv "$stage/upload" "$real" 2>/dev/null
|
||||
fi
|
||||
clear_upload_locked_result 0 "Unable to recreate upload directory" "$real"
|
||||
return
|
||||
fi
|
||||
else
|
||||
stage=
|
||||
fi
|
||||
|
||||
json_result 1 "" "$real"
|
||||
if [ "$live_exists" = "1" ]; then
|
||||
if ! rm -rf "$stage/upload"; then
|
||||
logger -t gecoosac "upload cleanup retained staged data at $stage"
|
||||
clear_upload_locked_result 0 "Unable to remove upload directory contents" "$real"
|
||||
return
|
||||
fi
|
||||
rmdir "$stage" || {
|
||||
clear_upload_locked_result 0 "Unable to remove upload cleanup stage" "$stage"
|
||||
return
|
||||
}
|
||||
fi
|
||||
|
||||
clear_upload_locked_result 1 "" "$real"
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
|
||||
Reference in New Issue
Block a user