From 0d4778f4d933f79cf3a5c8008f34d90463f67f46 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 23 Mar 2026 17:00:57 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=81=20Sync=202026-03-23=2017:00:57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- autoshare-ksmbd/Makefile | 2 +- autoshare-ksmbd/files/20-smb-ksmbd | 72 +-- autoshare-samba/Makefile | 2 +- autoshare-samba/files/20-smb | 67 ++- luci-app-amlogic/Makefile | 4 +- .../usr/share/amlogic/amlogic_check_plugin.sh | 10 + luci-app-openclawmgr/Makefile | 4 +- .../luci-static/resources/openclawmgr/app.js | 53 +- .../luasrc/controller/openclawmgr.lua | 62 ++- .../root/usr/libexec/istorec/openclawmgr.sh | 46 +- .../root/usr/share/openclawmgr/oc-config.sh | 6 + .../view/passwall/node_list/link_add_node.htm | 29 +- luci-app-pppoe-user/Makefile | 100 ---- luci-app-pppoe-user/ReadMe.md | 4 - .../resources/view/pppoe-user/downtimeuser.js | 47 -- .../resources/view/pppoe-user/interface.js | 22 - .../resources/view/pppoe-user/onlineuser.js | 169 ------- .../resources/view/pppoe-user/onu.js | 109 ---- .../resources/view/pppoe-user/user.js | 466 ------------------ .../po/templates/pppoe-user.pot | 170 ------- luci-app-pppoe-user/po/zh-cn | 1 - luci-app-pppoe-user/po/zh_Hans/pppoe-user.po | 167 ------- .../root/etc/config/pppoe-user | 13 - .../root/etc/hotplug.d/iface/30-interface | 9 - .../root/etc/init.d/pppoe-user | 180 ------- luci-app-pppoe-user/root/etc/ppp/ip-down | 41 -- .../root/etc/ppp/ip-down.d/offline-users | 58 --- .../root/etc/ppp/ip-down.d/speed-limit | 39 -- luci-app-pppoe-user/root/etc/ppp/ip-up | 41 -- .../root/etc/ppp/ip-up.d/online-users | 87 ---- .../root/etc/ppp/ip-up.d/speed-limit | 58 --- .../root/etc/uci-defaults/pppoe-user | 25 - .../luci/menu.d/luci-app-pppoe-user.json | 71 --- .../share/rpcd/acl.d/luci-app-pppoe-user.json | 20 - .../root/usr/share/rpcd/ucode/pppoe-ubus.uc | 29 -- .../root/usr/share/rpcd/ucode/pppoe-user.uc | 107 ---- .../share/ucitrack/luci-app-pppoe-user.json | 4 - luci-app-pppoe-user/screenshots/001.jpg | Bin 51381 -> 0 bytes luci-app-pppoe-user/screenshots/002.jpg | Bin 66636 -> 0 bytes luci-app-pppoe-user/screenshots/003.jpg | Bin 62477 -> 0 bytes .../luci-static/resources/view/samba4.js | 5 + pcat-manager/Makefile | 4 +- 42 files changed, 244 insertions(+), 2159 deletions(-) create mode 100755 luci-app-openclawmgr/root/usr/share/openclawmgr/oc-config.sh delete mode 100644 luci-app-pppoe-user/Makefile delete mode 100644 luci-app-pppoe-user/ReadMe.md delete mode 100644 luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/downtimeuser.js delete mode 100644 luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/interface.js delete mode 100644 luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onlineuser.js delete mode 100644 luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onu.js delete mode 100644 luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/user.js delete mode 100644 luci-app-pppoe-user/po/templates/pppoe-user.pot delete mode 120000 luci-app-pppoe-user/po/zh-cn delete mode 100644 luci-app-pppoe-user/po/zh_Hans/pppoe-user.po delete mode 100644 luci-app-pppoe-user/root/etc/config/pppoe-user delete mode 100644 luci-app-pppoe-user/root/etc/hotplug.d/iface/30-interface delete mode 100755 luci-app-pppoe-user/root/etc/init.d/pppoe-user delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-down delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-down.d/offline-users delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-down.d/speed-limit delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-up delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-up.d/online-users delete mode 100755 luci-app-pppoe-user/root/etc/ppp/ip-up.d/speed-limit delete mode 100644 luci-app-pppoe-user/root/etc/uci-defaults/pppoe-user delete mode 100644 luci-app-pppoe-user/root/usr/share/luci/menu.d/luci-app-pppoe-user.json delete mode 100644 luci-app-pppoe-user/root/usr/share/rpcd/acl.d/luci-app-pppoe-user.json delete mode 100644 luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-ubus.uc delete mode 100644 luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-user.uc delete mode 100644 luci-app-pppoe-user/root/usr/share/ucitrack/luci-app-pppoe-user.json delete mode 100644 luci-app-pppoe-user/screenshots/001.jpg delete mode 100644 luci-app-pppoe-user/screenshots/002.jpg delete mode 100644 luci-app-pppoe-user/screenshots/003.jpg diff --git a/autoshare-ksmbd/Makefile b/autoshare-ksmbd/Makefile index 2a087457..face98fc 100644 --- a/autoshare-ksmbd/Makefile +++ b/autoshare-ksmbd/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=autoshare-ksmbd PKG_VERSION:=1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_ARCH:=all include $(INCLUDE_DIR)/package.mk diff --git a/autoshare-ksmbd/files/20-smb-ksmbd b/autoshare-ksmbd/files/20-smb-ksmbd index 06de8508..790df8d9 100644 --- a/autoshare-ksmbd/files/20-smb-ksmbd +++ b/autoshare-ksmbd/files/20-smb-ksmbd @@ -1,12 +1,5 @@ #!/bin/sh -# -# D-Team Technology Co.,Ltd. ShenZhen -# 作者:Vic -# -# 警告:对着屏幕的哥们,我们允许你使用此脚本,但不允许你抹去作者的信息,请保留这段话。 -# - . /lib/functions.sh . /lib/functions/service.sh @@ -16,8 +9,9 @@ config_file="/etc/config/ksmbd" [ ! -f /etc/config/ksmbd ] && { echo " config globals - option 'workgroup' 'WORKGROUP' - option 'description' 'Ksmbd on OpenWrt' + option workgroup 'WORKGROUP' + option charset 'UTF-8' + option description 'Ksmbd on OpenWRT' " > $config_file } @@ -32,21 +26,27 @@ wait_for_init() { } smb_handle() { - config_get path $1 path - if [ "$path" = "$2" ] ;then - global=1 + local path + config_get path "$1" path + if [ -n "$path" ]; then + case "$path" in + "$2" | "$2"/*) global=1 ;; + esac + case "$2" in + "$path" | "$path"/*) global=1 ;; + esac fi } chk_en() { - config_get_bool autoshare $1 autoshare 1 - [ $autoshare -eq 0 ] && exit + config_get_bool autoshare "$1" autoshare 1 + [ "$autoshare" -eq 0 ] && exit } config_load ksmbd config_foreach chk_en ksmbd -device=`basename $DEVPATH` +device=`basename "$DEVPATH"` case "$ACTION" in add) @@ -55,6 +55,8 @@ case "$ACTION" in sd*);; md*);; hd*);; + mmcblk*);; + nvme*);; *) return;; esac @@ -62,22 +64,21 @@ case "$ACTION" in wait_for_init - [ "$(uci -q get ksmbd.@globals[0].autoshare)" == "1" ] && { - /etc/init.d/ksmbd restart - exit 0; - } - - cat /proc/mounts | grep -v '/boot\|/opt' | while read j + grep -v '/boot\|/opt' /proc/mounts | while read -r j do str=${j%% *} - if [ "$str" == $path ];then + if [ "$str" = "$path" ];then strr=${j#* } target=${strr%% *} global=0 - config_foreach smb_handle share $target + + config_load ksmbd + config_foreach smb_handle share "$target" + name=${target#*/mnt/} - name=$(echo $name | sed -e "s/^\///") - if [ $global -eq 0 ] ;then + name=$(echo "$name" | sed -e "s/^\///") + + if [ "$global" -eq 0 ] ;then echo -e "\n\nconfig share" >> $config_file echo -e "\toption auto '1'" >> $config_file echo -e "\toption name '$name'" >> $config_file @@ -93,27 +94,26 @@ case "$ACTION" in fi fi done - uci -q set ksmbd.@globals[0].autoshare='1' - uci commit ksmbd ;; remove) i=0 while true do - dev=`uci get ksmbd.@share[$i].device` - [ $? -ne 0 ] && break + if ! uci -q get ksmbd.@share[$i] >/dev/null; then + break + fi - [ "$dev" = "$device" ] && { - auto=`uci get ksmbd.@share[$i].auto` - [ $auto = "1" ] && { - mount_dir=`uci get ksmbd.@share[$i].name` + dev=$(uci -q get ksmbd.@share[$i].device) + if [ "$dev" = "$device" ]; then + auto=$(uci -q get ksmbd.@share[$i].auto) + if [ "$auto" = "1" ]; then uci delete ksmbd.@share[$i] - uci commit + uci commit ksmbd /etc/init.d/ksmbd reload return - } - } + fi + fi let i+=1 done ;; diff --git a/autoshare-samba/Makefile b/autoshare-samba/Makefile index 4fd2ad15..09198a70 100644 --- a/autoshare-samba/Makefile +++ b/autoshare-samba/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=autoshare-samba PKG_VERSION:=1 -PKG_RELEASE:=1 +PKG_RELEASE:=2 PKG_ARCH:=all include $(INCLUDE_DIR)/package.mk diff --git a/autoshare-samba/files/20-smb b/autoshare-samba/files/20-smb index 1e2d3bec..236d07c3 100644 --- a/autoshare-samba/files/20-smb +++ b/autoshare-samba/files/20-smb @@ -1,12 +1,5 @@ #!/bin/sh -# -# D-Team Technology Co.,Ltd. ShenZhen -# 作者:Vic -# -# 警告:对着屏幕的哥们,我们允许你使用此脚本,但不允许你抹去作者的信息,请保留这段话。 -# - . /lib/functions.sh . /lib/functions/service.sh @@ -33,21 +26,27 @@ wait_for_init() { } smb_handle() { - config_get path $1 path - if [ "$path" = "$2" ] ;then - global=1 + local path + config_get path "$1" path + if [ -n "$path" ]; then + case "$path" in + "$2" | "$2"/*) global=1 ;; + esac + case "$2" in + "$path" | "$path"/*) global=1 ;; + esac fi } chk_en() { - config_get_bool autoshare $1 autoshare 1 - [ $autoshare -eq 0 ] && exit + config_get_bool autoshare "$1" autoshare 1 + [ "$autoshare" -eq 0 ] && exit } config_load samba4 config_foreach chk_en samba4 -device=`basename $DEVPATH` +device=`basename "$DEVPATH"` case "$ACTION" in add) @@ -56,6 +55,8 @@ case "$ACTION" in sd*);; md*);; hd*);; + mmcblk*);; + nvme*);; *) return;; esac @@ -63,22 +64,21 @@ case "$ACTION" in wait_for_init - [ "$(uci -q get samba4.@samba[0].autoshare)" == "1" ] && { - /etc/init.d/samba4 restart - exit 0; - } - - cat /proc/mounts | grep -v '/boot\|/opt' | while read j + grep -v '/boot\|/opt' /proc/mounts | while read -r j do str=${j%% *} - if [ "$str" == $path ];then + if [ "$str" = "$path" ];then strr=${j#* } target=${strr%% *} global=0 - config_foreach smb_handle sambashare $target + + config_load samba4 + config_foreach smb_handle sambashare "$target" + name=${target#*/mnt/} - name=$(echo $name | sed -e "s/^\///") - if [ $global -eq 0 ] ;then + name=$(echo "$name" | sed -e "s/^\///") + + if [ "$global" -eq 0 ] ;then echo -e "\n\nconfig sambashare" >> $config_file echo -e "\toption auto '1'" >> $config_file echo -e "\toption name '$name'" >> $config_file @@ -94,27 +94,26 @@ case "$ACTION" in fi fi done - uci -q set samba4.@samba[0].autoshare='1' - uci commit samba4 ;; remove) i=0 while true do - dev=`uci get samba4.@sambashare[$i].device` - [ $? -ne 0 ] && break + if ! uci -q get samba4.@sambashare[$i] >/dev/null; then + break + fi - [ "$dev" = "$device" ] && { - auto=`uci get samba4.@sambashare[$i].auto` - [ $auto = "1" ] && { - mount_dir=`uci get samba4.@sambashare[$i].name` + dev=$(uci -q get samba4.@sambashare[$i].device) + if [ "$dev" = "$device" ]; then + auto=$(uci -q get samba4.@sambashare[$i].auto) + if [ "$auto" = "1" ]; then uci delete samba4.@sambashare[$i] - uci commit + uci commit samba4 /etc/init.d/samba4 reload return - } - } + fi + fi let i+=1 done ;; diff --git a/luci-app-amlogic/Makefile b/luci-app-amlogic/Makefile index 3fa63848..eb70a385 100644 --- a/luci-app-amlogic/Makefile +++ b/luci-app-amlogic/Makefile @@ -16,8 +16,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-amlogic -PKG_VERSION:=3.1.286 -PKG_RELEASE:=1 +PKG_VERSION:=3.1.287 +PKG_RELEASE:=2 PKG_LICENSE:=GPL-2.0 License PKG_MAINTAINER:=ophub diff --git a/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh index 5efc3822..0f18f14c 100755 --- a/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh +++ b/luci-app-amlogic/root/usr/share/amlogic/amlogic_check_plugin.sh @@ -159,6 +159,16 @@ else [[ "${?}" -ne "0" ]] && tolog "02.05 Language pack [ ${langfile} ] download failed." "1" done + # The .apk filename is preceded by a tilde (~) instead of a dot (.). + for file in ${TMP_CHECK_DIR}/*.apk; do + [[ -f "${file}" ]] || continue + base_name="$(basename "${file}")" + new_name="$(echo "${base_name}" | sed -E 's/\.([a-f0-9]{7}\.apk)/~\1/')" + if [[ "${base_name}" != "${new_name}" ]]; then + mv -f "${file}" "${TMP_CHECK_DIR}/${new_name}" || true + fi + done + sync && sleep 2 fi diff --git a/luci-app-openclawmgr/Makefile b/luci-app-openclawmgr/Makefile index 3a62fc5f..b51829eb 100644 --- a/luci-app-openclawmgr/Makefile +++ b/luci-app-openclawmgr/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk -PKG_VERSION:=0.1.5 -PKG_RELEASE:=6 +PKG_VERSION:=0.1.6 +PKG_RELEASE:=7 LUCI_TITLE:=LuCI support for OpenClaw Launcher LUCI_PKGARCH:=all diff --git a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js index 9c88740f..60b25631 100644 --- a/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js +++ b/luci-app-openclawmgr/htdocs/luci-static/resources/openclawmgr/app.js @@ -130,12 +130,14 @@ if (status.installing) return "安装中"; if (!status || !status.installed) return "未安装"; if (status.running) return "运行中"; + if (status.reachable) return "运行中(未托管)"; return "已停止"; } function statusDotClass(status) { if (status && status.installing) return ""; if (status && status.running) return "is-success"; + if (status && status.reachable) return ""; return "is-danger"; } @@ -382,11 +384,8 @@ var savingAi = state.savingSection === "ai"; var savingAccess = state.savingSection === "access"; - var serviceButtons = showServiceActions ? ( - (!status.running ? '' : '') + - (status.running ? '' : '') + - '' - ) : ''; + var canStartService = !status.running && !status.reachable; + var canStopService = !!status.running; root.innerHTML = '' + @@ -415,7 +414,7 @@ '' + '' + '' + - '' + + '' + '' + '' + '
安装任务正在后台运行,点击“安装中”可继续查看日志。
' + @@ -438,7 +437,15 @@ ["auto", "自动"] ])) + fieldInput("数据目录", '' + baseDirOptions + '') + - '
' + serviceButtons + (state.lastAppliedAt ? '已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置' : '') + '
' + + '
' + + '' + + '' + + '' + + '' + + '' + + '' + + (state.lastAppliedAt ? '已于 ' + escapeHtml(state.lastAppliedAt) + ' 更新配置' : '') + + '
' + '' + '
' + @@ -485,6 +492,7 @@ function updateStatusDom(status) { status = status || {}; + var gatewayActive = !!(status.running || status.reachable); function byId(id) { if (root.getElementById) return root.getElementById(id); @@ -565,15 +573,40 @@ else cancelInstallBtn.classList.add("oclm-hidden"); } if (openConsoleBtn) { - if (status.running) openConsoleBtn.classList.remove("oclm-hidden"); + if (gatewayActive) openConsoleBtn.classList.remove("oclm-hidden"); else openConsoleBtn.classList.add("oclm-hidden"); - openConsoleBtn.disabled = !(status.running && state.consoleReady); + openConsoleBtn.disabled = !state.consoleReady; openConsoleBtn.innerHTML = openclawIcon("oclm-button-icon") + (state.consoleReady ? "打开控制台" : "控制台准备中…"); } if (noteEl) { if (status.installing) noteEl.classList.remove("oclm-hidden"); else noteEl.classList.add("oclm-hidden"); } + + var svcWrap = byId("oclm-service-actions"); + var btnStart = byId("oclm-btn-start"); + var btnStop = byId("oclm-btn-stop"); + var btnRestart = byId("oclm-btn-restart"); + var showServiceActions = !!(status.installed && !status.installing); + var canStartService = !!(!status.running && !status.reachable); + var canStopService = !!status.running; + + if (svcWrap) { + if (showServiceActions) svcWrap.classList.remove("oclm-hidden"); + else svcWrap.classList.add("oclm-hidden"); + } + if (btnStart) { + if (showServiceActions && canStartService) btnStart.classList.remove("oclm-hidden"); + else btnStart.classList.add("oclm-hidden"); + } + if (btnStop) { + if (showServiceActions && canStopService) btnStop.classList.remove("oclm-hidden"); + else btnStop.classList.add("oclm-hidden"); + } + if (btnRestart) { + if (showServiceActions) btnRestart.classList.remove("oclm-hidden"); + else btnRestart.classList.add("oclm-hidden"); + } } function fieldInput(label, control) { @@ -954,7 +987,7 @@ function refreshStatus(done) { request(config.statusUrl).then(function(data) { state.status = data || {}; - if (state.status && state.status.running) { + if (state.status && (state.status.running || state.status.reachable)) { if (!state.consoleReady) { pollConsoleReady(20); } diff --git a/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua b/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua index f6598e6d..64def85c 100644 --- a/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua +++ b/luci-app-openclawmgr/luasrc/controller/openclawmgr.lua @@ -353,6 +353,46 @@ local function get_pid_uptime_human(pid) return fmt_elapsed(elapsed) end +local function probe_gateway_ready(port, base_dir, bind) + local sys = require "luci.sys" + local util = require "luci.util" + + if not port or not tostring(port):match("^%d+$") then + return false, "", "" + end + if not base_dir or base_dir == "" then + return false, "", "" + end + + local base_path = configured_base_path(base_dir) + local candidates = {} + + if bind == "lan" or bind == "auto" then + local ip = lan_ipv4() + if ip ~= "" then + candidates[#candidates + 1] = ip + end + end + candidates[#candidates + 1] = "127.0.0.1" + + local last_code, last_url = "", "" + for _, host in ipairs(candidates) do + local url = "http://" .. host .. ":" .. port .. base_path + last_url = url + local cmd = string.format( + "curl -fsS -o /dev/null --connect-timeout 1 --max-time 2 -w '%%{http_code}' %s 2>/dev/null", + util.shellquote(url) + ) + local code = sys.exec(cmd):gsub("%s+$", "") + last_code = code + local n = tonumber(code) or 0 + if n >= 200 and n < 400 then + return true, code, url + end + end + return false, last_code, last_url +end + function action_status() local sys = require "luci.sys" local uci = require "luci.model.uci".cursor() @@ -373,6 +413,11 @@ function action_status() running = (st == "running") installed = (st == "running" or st == "stopped") end + + local reachable, reachable_code, reachable_url = false, "", "" + if installed and not running then + reachable, reachable_code, reachable_url = probe_gateway_ready(port, base_dir, bind) + end local lock_running, lock_pid = installer_lock_running() local installing = (task.running and (task.op == "install" or task.op == "upgrade")) or lock_running if not installing and task.running and not installed and not running then @@ -405,6 +450,9 @@ function action_status() enabled = enabled, installed = installed, running = running, + reachable = reachable, + reachable_http_code = reachable_code, + reachable_url = reachable_url, task_running = task.running, task_op = task.op, installing = installing, @@ -423,11 +471,10 @@ function action_status() end function action_ready() - local sys = require "luci.sys" - local util = require "luci.util" local uci = require "luci.model.uci".cursor() local port = uci:get("openclawmgr", "main", "port") or "18789" + local bind = uci:get("openclawmgr", "main", "bind") or "lan" local base_dir = uci:get("openclawmgr", "main", "base_dir") or "" if not port:match("^%d+$") then port = "18789" end @@ -437,20 +484,13 @@ function action_ready() return end - local base_url = "http://127.0.0.1:" .. port .. configured_base_path(base_dir) - local cmd = string.format( - "curl -fsS -o /dev/null --connect-timeout 1 --max-time 2 -w '%%{http_code}' %s 2>/dev/null", - util.shellquote(base_url) - ) - local code = sys.exec(cmd):gsub("%s+$", "") - local n = tonumber(code) or 0 - local ready = (n >= 200 and n < 400) + local ready, code, url = probe_gateway_ready(port, base_dir, bind) write_json({ ok = true, ready = ready, http_code = code, - url = base_url, + url = url, }) end diff --git a/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh b/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh index d8cc1edb..399c462e 100755 --- a/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh +++ b/luci-app-openclawmgr/root/usr/libexec/istorec/openclawmgr.sh @@ -559,15 +559,14 @@ if selected_env_key and selected_api_key ~= "" then end cfg.env = next(env) and env or nil -local models = {} -models.mode = "merge" -local providers = {} -models.providers = providers -cfg.models = models + local models = ensure_table(cfg, "models") + if type(models.mode) ~= "string" or models.mode == "" then + models.mode = "merge" + end + local providers = ensure_table(models, "providers") -local current_provider_id = os.getenv("DEFAULT_AGENT_NAME") or "anthropic" -local current_provider = {} -providers[current_provider_id] = current_provider + local current_provider_id = os.getenv("DEFAULT_AGENT_NAME") or "anthropic" + local current_provider = ensure_table(providers, current_provider_id) if current_provider_id == "openai" then current_provider.api = "openai-completions" @@ -600,13 +599,30 @@ elseif current_provider_id == "moonshot" then } end -local override_base = os.getenv("DEFAULT_AGENT_OVERRIDE_BASE_URL") or "" -local base_url_mode = os.getenv("DEFAULT_AGENT_BASE_URL_MODE") or "default" -if base_url_mode == "override" and override_base ~= "" then - current_provider.baseUrl = override_base -elseif base_url_mode == "default" then - current_provider.baseUrl = os.getenv("DEFAULT_AGENT_BASE_URL") or current_provider.baseUrl -end + local override_base = os.getenv("DEFAULT_AGENT_OVERRIDE_BASE_URL") or "" + local base_url_mode = os.getenv("DEFAULT_AGENT_BASE_URL_MODE") or "default" + if base_url_mode == "override" and override_base ~= "" then + current_provider.baseUrl = override_base + elseif base_url_mode == "default" then + current_provider.baseUrl = os.getenv("DEFAULT_AGENT_BASE_URL") or current_provider.baseUrl + end + + -- luci.jsonc encodes empty Lua tables as JSON arrays ([]). To avoid producing + -- invalid provider entries like {"deepseek/deepseek-chat":[]}, drop provider + -- records that are empty or look like a provider/model string. + do + local to_del = {} + for k, v in pairs(providers) do + if type(k) == "string" and k:find("/", 1, true) then + table.insert(to_del, k) + elseif type(v) == "table" and next(v) == nil then + table.insert(to_del, k) + end + end + for _, k in ipairs(to_del) do + providers[k] = nil + end + end local agents = ensure_table(cfg, "agents") local defaults = ensure_table(agents, "defaults") diff --git a/luci-app-openclawmgr/root/usr/share/openclawmgr/oc-config.sh b/luci-app-openclawmgr/root/usr/share/openclawmgr/oc-config.sh new file mode 100755 index 00000000..cdd43576 --- /dev/null +++ b/luci-app-openclawmgr/root/usr/share/openclawmgr/oc-config.sh @@ -0,0 +1,6 @@ +#!/bin/sh +# Backward-compatible wrapper. New entry: openclawmgr-cli.sh + +set -eu + +exec /usr/share/openclawmgr/openclawmgr-cli.sh "$@" diff --git a/luci-app-passwall/luasrc/view/passwall/node_list/link_add_node.htm b/luci-app-passwall/luasrc/view/passwall/node_list/link_add_node.htm index d7ee0966..edbbec22 100644 --- a/luci-app-passwall/luasrc/view/passwall/node_list/link_add_node.htm +++ b/luci-app-passwall/luasrc/view/passwall/node_list/link_add_node.htm @@ -40,6 +40,22 @@ local api = require "luci.passwall.api" sendNextChunk(); } + function decodeIfBase64(str) { + try { + let s = str.replace(/-/g, '+').replace(/_/g, '/'); + while (s.length % 4) s += '='; + const decoded = decodeURIComponent( + atob(s).split('').map(c => + '%' + c.charCodeAt(0).toString(16).padStart(2, '0') + ).join('') + ); + if (btoa(unescape(encodeURIComponent(decoded))).replace(/=+$/, '') === s.replace(/=+$/, '')) { + return decoded; + } + } catch (e) {} + return str; + } + function getBg(el) { if (!el) return null; const style = getComputedStyle(el); @@ -74,15 +90,14 @@ local api = require "luci.passwall.api" const group = (document.querySelector('#addlink_group_custom input[type="hidden"]')?.value || "default"); nodes_link = nodes_link.replace(/\t/g, "").replace(/\r\n|\r/g, "\n").replace(/<[^>]*>/g, '').trim(); if (nodes_link != "") { + nodes_link = decodeIfBase64(nodes_link); let s = nodes_link.split('://'); if (s.length > 1) { ajax_add_node(nodes_link, group); - } - else { + } else { alert("<%:Please enter the correct link.%>"); } - } - else { + } else { document.getElementById("nodes_link").focus(); } } @@ -93,8 +108,7 @@ local api = require "luci.passwall.api" function(x, data) { if(x && x.status == 200) { window.location.href = '<%=api.url("node_list")%>'; - } - else { + } else { alert("<%:Error%>"); } }); @@ -154,8 +168,7 @@ local api = require "luci.passwall.api" function(x, data) { if (x && x.status == 200) { window.location.href = '<%=api.url("node_list")%>'; - } - else { + } else { alert("<%:Error%>"); } }); diff --git a/luci-app-pppoe-user/Makefile b/luci-app-pppoe-user/Makefile deleted file mode 100644 index 9b5eaf16..00000000 --- a/luci-app-pppoe-user/Makefile +++ /dev/null @@ -1,100 +0,0 @@ -include $(TOPDIR)/rules.mk - -LUCI_TITLE:=PPPoE Server User Management (Modern JS/Ucode) -LUCI_DEPENDS:=+luci-compat +kmod-nft-connlimit +ucode +rpcd +ppp +ppp-mod-pppoe -LUCI_PKGARCH:=all -PKG_VERSION:=2.0 -PKG_RELEASE:=2 - -# 定义配置文件,升级时保留 -define Package/luci-app-pppoe-user/conffiles -/etc/config/pppoe-user -endef - -# 预安装脚本:清理旧版本残留 -define Package/luci-app-pppoe-user/preinst -#!/bin/sh -if [ -z "$${IPKG_INSTROOT}" ]; then - # 仅在运行时清理,安装到新根文件系统时不清理 - if [ -f /etc/init.d/pppoe-user ]; then - /etc/init.d/pppoe-user stop 2>/dev/null || true - fi - # 清理旧的 Lua 视图缓存 - rm -rf /tmp/luci-modulecache/* - rm -rf /tmp/luci-indexcache/* -fi -exit 0 -endef - -define Package/luci-app-pppoe-user/install - # --- 1. I18N (让 luci.mk 自动处理,或手动编译) --- - # 注意:现代 luci.mk 会自动扫描 po 目录并编译。 - # 如果必须手动指定,确保编译为 .lua 或 .json (视版本而定) - # 这里我们依赖 luci.mk 的默认行为,只需确保 po 目录存在即可。 - # 如果 luci.mk 没有自动安装,取消下面注释: - # $(INSTALL_DIR) $(1)/usr/lib/lua/luci/i18n - # $(foreach po,$(wildcard ./po/*/pppoe-user.po), \ - # $(call Build/install-po,$(po),$(1)/usr/lib/lua/luci/i18n) \ - # ) - - # --- 2. LuCI JS Views (Modern Path) --- - $(INSTALL_DIR) $(1)/usr/share/luci/static/resources/view/pppoe-user - $(INSTALL_DATA) ./htdocs/luci-static/resources/view/pppoe-user/*.js \ - $(1)/usr/share/luci/static/resources/view/pppoe-user/ - - # --- 3. Ucode Scripts --- - $(INSTALL_DIR) $(1)/usr/share/ucode - $(INSTALL_DATA) ./root/usr/share/ucode/*.uc \ - $(1)/usr/share/ucode/ - # 确保 ucode 脚本可执行 (虽然不是必须,因为通过解释器调用,但习惯上加上) - chmod 644 $(1)/usr/share/ucode/*.uc - - # --- 4. RPCD ACL --- - $(INSTALL_DIR) $(1)/usr/share/rpcd/acl.d - $(INSTALL_DATA) ./root/usr/share/rpcd/acl.d/*.json \ - $(1)/usr/share/rpcd/acl.d/ - - # --- 5. System Configuration --- - $(INSTALL_DIR) $(1)/etc/config - $(INSTALL_CONF) ./root/etc/config/pppoe-user \ - $(1)/etc/config/ - - # --- 6. Init Scripts --- - $(INSTALL_DIR) $(1)/etc/init.d - $(INSTALL_BIN) ./root/etc/init.d/pppoe-user \ - $(1)/etc/init.d/ - - # --- 7. PPP Scripts --- - $(INSTALL_DIR) $(1)/etc/ppp - $(INSTALL_BIN) ./root/etc/ppp/ip-up \ - $(1)/etc/ppp/ - $(INSTALL_BIN) ./root/etc/ppp/ip-down \ - $(1)/etc/ppp/ - - $(INSTALL_DIR) $(1)/etc/ppp/ip-up.d - $(INSTALL_BIN) ./root/etc/ppp/ip-up.d/* \ - $(1)/etc/ppp/ip-up.d/ - - $(INSTALL_DIR) $(1)/etc/ppp/ip-down.d - $(INSTALL_BIN) ./root/etc/ppp/ip-down.d/* \ - $(1)/etc/ppp/ip-down.d/ - - # --- 8. Hotplug Scripts --- - $(INSTALL_DIR) $(1)/etc/hotplug.d/iface - $(INSTALL_BIN) ./root/etc/hotplug.d/iface/* \ - $(1)/etc/hotplug.d/iface/ - - # --- 9. UCI Defaults --- - $(INSTALL_DIR) $(1)/etc/uci-defaults - $(INSTALL_BIN) ./root/etc/uci-defaults/pppoe-user \ - $(1)/etc/uci-defaults/ - - # --- 10. LuCI Menu --- - $(INSTALL_DIR) $(1)/usr/share/luci/menu.d - $(INSTALL_DATA) ./root/usr/share/luci/menu.d/*.json \ - $(1)/usr/share/luci/menu.d/ -endef - -# 调用标准的 luci.mk 构建规则 -# 它会自动处理 i18n 编译和元数据生成 -include $(TOPDIR)/feeds/luci/luci.mk diff --git a/luci-app-pppoe-user/ReadMe.md b/luci-app-pppoe-user/ReadMe.md deleted file mode 100644 index 0444ed4a..00000000 --- a/luci-app-pppoe-user/ReadMe.md +++ /dev/null @@ -1,4 +0,0 @@ -# luci-app-pppoe-user - -OpenWrt Luci PPPoE dial-up user management application -Need to be used with the installation of rp-pppoe software package diff --git a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/downtimeuser.js b/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/downtimeuser.js deleted file mode 100644 index 5d7a0452..00000000 --- a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/downtimeuser.js +++ /dev/null @@ -1,47 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require uci'; - -return view.extend({ - load: function() { - return uci.load('pppoe-user'); - }, - render: function() { - var users = uci.sections('pppoe-user', 'user'); - var downUsers = users.filter(u => u.enabled == '0'); - - var m = new form.Map('pppoe-user'); - var s = m.section(form.TableSection, 'downtime', _('Downtime User [%d]').format(downUsers.length)); - s.anonymous = true; - s.addremove = false; - - // 填充数据 - s.section = function(section_id) { - // 手动注入数据到 section - return this.super('section', section_id); - }; - - // 由于 TableSection 通常绑定 UCI,这里我们用 filter 后的数据比较麻烦 - // 简单做法:遍历 downUsers 手动构建表格,或者使用 GridSection 并过滤 render - // 这里采用直接构建表格的方式以保持清晰 - - return E('div', { class: 'cbi-map' }, [ - E('h2', _('Downtime User [%d]').format(downUsers.length)), - E('table', { class: 'table' }, [ - E('tr', { class: 'tr table-titles' }, [ - E('th', { class: 'th' }, _('Username')), - E('th', { class: 'th' }, _('MAC')), - E('th', { class: 'th' }, _('Package')), - E('th', { class: 'th' }, _('Expiration')) - ]), - ...downUsers.map(u => E('tr', { class: 'tr cbi-rowstyle-1' }, [ - E('td', { class: 'td' }, u.username), - E('td', { class: 'td' }, u.macaddr || '-'), - E('td', { class: 'td' }, u.package), - E('td', { class: 'td' }, u.expires) - ])) - ]) - ]); - } -}); diff --git a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/interface.js b/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/interface.js deleted file mode 100644 index 3137cdbe..00000000 --- a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/interface.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; -'require view'; -'require fs'; - -return view.extend({ - load: function() { - return fs.read('/var/pppoe-user/log/interface.log'); - }, - render: function(logs) { - var m = new form.Map('pppoe-user'); - var s = m.section(form.NamedSection, 'logview', 'dummy'); - - var o = s.option(form.TextValue, '_log'); - o.rows = 30; - o.readonly = true; - o.cfgvalue = function() { - return logs || _('No log available.'); - }; - - return m.render(); - } -}); diff --git a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onlineuser.js b/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onlineuser.js deleted file mode 100644 index 29815cbd..00000000 --- a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onlineuser.js +++ /dev/null @@ -1,169 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require fs'; -'require ubus'; -'require ui'; - -return view.extend({ - load: function() { - return Promise.all([ - fs.read('/proc/net/dev'), - fs.list('/var/etc/pppoe-user/session') - ]).then(function(data) { - let devContent = data[0] || ''; - let files = data[1] || []; - - let pppCount = 0; - devContent.split(/\n/).forEach(function(line) { - if (/^\s*ppp/.test(line)) pppCount++; - }); - - let sessions = []; - let promises = files.map(function(f) { - if (f.name.endsWith('.json')) { - return fs.read('/var/etc/pppoe-user/session/' + f.name).then(function(content) { - try { - let obj = JSON.parse(content); - obj.session_file = '/var/etc/pppoe-user/session/' + f.name; - sessions.push(obj); - } catch(e) {} - }); - } - }); - - return Promise.all(promises).then(function() { - return { count: pppCount, sessions: sessions }; - }); - }); - }, - - render: function(data) { - var m, s, o; - var tableData = data.sessions || []; - - m = new form.Map('pppoe-user'); - s = m.section(form.TableSection, 'sessions', _('Online Users [%d]').format(data.count)); - s.anonymous = true; - s.addremove = false; - s.sortable = false; - s.nodescriptions = true; - - o = s.option(form.DummyValue, 'username', _('User Name')); - o = s.option(form.DummyValue, 'mac', _('MAC address')); - o = s.option(form.DummyValue, 'interface', _('Interface')); - o = s.option(form.DummyValue, 'ip', _('IP address')); - o = s.option(form.DummyValue, 'package', _('Package')); - o = s.option(form.DummyValue, 'updated', _('Renewal Date')); - o = s.option(form.DummyValue, 'uptime', _('Up Time')); - - var btn = s.option(form.Button, 'kill', _('Forced Offline')); - btn.inputstyle = 'reset'; - btn.onclick = function(ev, section_id) { - var row = tableData.find(function(r) { return r.username === section_id; }); - // 注意:TableSection 的 section_id 通常是配置名,这里我们是动态数据,需特殊处理 - // 更好的方式是将 username 作为 key 或使用 custom render - // 此处简化:假设我们能获取到 row 数据 - // 实际开发中,建议使用 form.GridSection 配合 load 数据映射,或者自定义 HTML - // 下面展示一种通过 data-attribute 传递参数的方法 - - // 由于 TableSection 处理动态非 UCI 数据较麻烦,这里采用更直接的 UI 构建方式 - // 或者在 render 中手动构建表格。 - // 为了保持代码简洁,这里演示核心逻辑: - - var targetRow = this.map.findElement('id', 'cbi.pppoe-user.sessions.' + section_id); - // 获取该行对应的真实数据 (需要在 render 时将数据绑定到 DOM 或全局变量) - // 鉴于复杂度,推荐直接使用 L.ui.showModal 或 自定义 renderContent - }; - - // 【更优解】:对于非 UCI 的动态列表,直接返回 HTML 往往比 form.TableSection 更灵活 - // 但为了保持风格统一,我们假设用户能理解需要自定义 onclick 来获取数据 - - // 重新实现 onclick 以获取正确数据 - btn.onclick = L.bind(function(ev, section_id) { - // 在 load 阶段我们将数据存到了 this.sessionsData - var session = this.sessionsData.find(s => s.username === section_id); - if (!session) return; - - return ui.showModal(_('Confirm'), [ - E('p', _('Are you sure you want to force offline user "%s"?').format(session.username)), - E('div', { class: 'right' }, [ - E('button', { - class: 'btn', - click: ui.hideModal - }, [ _('Cancel') ]), - ' ', - E('button', { - class: 'btn cbi-button-action', - click: ui.handler(L.bind(function() { - return ubus.call('pppoe.user', 'kill', { - session_file: session.session_file, - pid: session.pid - }).then(() => { - ui.addNotification(null, E('p', _('User killed successfully'))); - this.load().then(d => this.render(d)); // 刷新 - }).catch(e => { - ui.addNotification(null, E('p', _('Error: ') + e.message)); - }); - }, this)) - }, [ _('OK') ]) - ]) - ]); - }, this); - - // 需要将数据挂载到 this 以便 onclick 访问 - this.sessionsData = tableData; - - // 覆盖 renderSection 以正确映射 section_id 到 username - s.renderSection = function(section_id) { - // 这里的 section_id 其实是 username,因为我们在 load 后需要手动映射 - // 这种动态数据最好用 form.GridSection 的 load/save 钩子,或者直接手写 HTML - // 简单起见,这里假设 section_id 就是 username (需在 section 定义时指定) - return this.super('renderSection', section_id); - }; - - // 修正:TableSection 默认基于 UCI config。对于纯动态数据, - // 建议重写 render 函数直接生成 HTML 表格,不使用 form.Map 的自动渲染 - // 下面提供一个直接渲染 HTML 的版本思路: - - return E('div', { class: 'cbi-map' }, [ - E('h2', _('Online Users [%d]').format(data.count)), - E('table', { class: 'table' }, [ - E('tr', { class: 'tr table-titles' }, [ - E('th', { class: 'th' }, _('User Name')), - E('th', { class: 'th' }, _('IP')), - E('th', { class: 'th' }, _('MAC')), - E('th', { class: 'th' }, _('Action')) - ]), - ...tableData.map(user => E('tr', { class: 'tr cbi-rowstyle-' + ((Math.random() > 0.5) ? '1' : '2') }, [ - E('td', { class: 'td' }, user.username), - E('td', { class: 'td' }, user.ip), - E('td', { class: 'td' }, user.mac), - E('td', { class: 'td' }, [ - E('button', { - class: 'btn cbi-button-action', - click: () => { - // 同上 kill 逻辑 - ui.showModal(_('Confirm'), [ - E('p', _('Kill %s?').format(user.username)), - E('div', { class: 'right' }, [ - E('button', { class: 'btn', click: ui.hideModal }, _('Cancel')), - ' ', - E('button', { - class: 'btn cbi-button-negative', - click: () => { - ubus.call('pppoe.user', 'kill', { session_file: user.session_file, pid: user.pid }) - .then(() => location.reload()) - .catch(e => alert(e)); - } - }, _('Kill')) - ]) - ]); - } - }, _('Forced Offline')) - ]) - ])) - ]) - ]); - } -}); diff --git a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onu.js b/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onu.js deleted file mode 100644 index 105b5b80..00000000 --- a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/onu.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require ui'; - -return view.extend({ - render: function () { - var m, s, o; - - m = new form.Map('pppoe-user', _(''), _('')); - - // User section - s = m.section(form.GridSection, 'user', _('ONU List')); - s.anonymous = true; - s.nodescriptions = true - - // Username field - o = s.option(form.Value, 'username', _('Account')); - o.readonly = true; - - // Service Name field (dropdown) - o = s.option(form.Value, 'servicename', _('Service Name')); - o.modalonly = true; - o.readonly = true; - - // Password field - o = s.option(form.Value, 'password', _('Password')); - o.password = true; - o.modalonly = true; - o.readonly = true; - - // MAC Address field (dropdown) - o = s.option(form.Value, 'macaddr', _('MAC Address')); - o.password = true; - o.modalonly = true; - o.readonly = true; - - // Package field (dropdown) - o = s.option(form.Value, 'package', _('Package')); - o.readonly = true; - - // Upload Speed field (dropdown) - var o = s.option(form.Value, 'urate', _('Upload Speed')); - o.modalonly = true; - o.readonly = true; - - // Download Speed field (dropdown) - var o = s.option(form.Value, 'drate', _('Download Speed')); - o.modalonly = true; - o.readonly = true; - - // Concurrent Connection Number Segment (dropdown menu) - var o = s.option(form.Value, 'connect', _('Connection Number')); - o.modalonly = true; - o.readonly = true; - - // OLT field (dropdown) - var o = s.option(form.Value, 'olt', _('OLT')); - o.value('1', 'OLT 1'); - o.value('2', 'OLT 2'); - o.value('3', 'OLT 3'); - o.value('4', 'OLT 4'); - o.value('5', 'OLT 5'); - o.value('6', 'OLT 6'); - o.value('7', 'OLT 7'); - o.value('8', 'OLT 8'); - o.value('9', 'OLT 9'); - o.value('10', 'OLT 10'); - o.value('11', 'OLT 11'); - o.value('12', 'OLT 12'); - o.value('13', 'OLT 13'); - o.value('14', 'OLT 14'); - o.value('15', 'OLT 15'); - o.value('16', 'OLT 16'); - o.value('17', 'OLT 17'); - o.value('18', 'OLT 18'); - o.value('19', 'OLT 19'); - o.value('20', 'OLT 20'); - - // PON field (dropdown) - var o = s.option(form.Value, 'pon', _('PON')); - o.value('1', 'PON 1'); - o.value('2', 'PON 2'); - o.value('3', 'PON 3'); - o.value('4', 'PON 4'); - o.value('5', 'PON 5'); - o.value('6', 'PON 6'); - o.value('7', 'PON 7'); - o.value('8', 'PON 8'); - o.value('9', 'PON 9'); - o.value('10', 'PON 10'); - o.value('11', 'PON 11'); - o.value('12', 'PON 12'); - o.value('13', 'PON 13'); - o.value('14', 'PON 14'); - o.value('15', 'PON 15'); - o.value('16', 'PON 16'); - - // Serial Number field (dropdown) - o = s.option(form.Value, 'sn', _('S/N')); - o.placeholder = 'ONT Serial Number'; - - // Submit button - return m.render(); - }, - handleSave: null, - handleSaveApply: null, - handleReset: null -}); diff --git a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/user.js b/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/user.js deleted file mode 100644 index e664906f..00000000 --- a/luci-app-pppoe-user/htdocs/luci-static/resources/view/pppoe-user/user.js +++ /dev/null @@ -1,466 +0,0 @@ -'use strict'; -'require view'; -'require form'; -'require ui'; -'require uci'; - -return view.extend({ - render: function () { - var m, s, o; - - m = new form.Map('pppoe-user', _(''), _('')); - - // User section - s = m.section(form.GridSection, 'user', _('User List')); - s.anonymous = true; - s.addremove = true; - s.editable = false; - s.nodescriptions = true; - s.sortable = false; - - // Enable User field - o = s.option(form.Flag, 'enabled', _('Enable')); - o.rmempty = false; // Make the field required - o.default = "1"; - - // Username field - o = s.option(form.Value, 'username', _('Account')); - o.rmempty = false; // Make the field required - o.placeholder = _('Required'); - o.validate = function (section_id, value) { - // Validate the input value to match the alphanumeric format - if (!/^[a-zA-Z0-9]+$/.test(value)) { - return _('Invalid username format. Only alphanumeric characters are allowed.'); - } - - // Check the length of the username - if (value.length < 4 || value.length > 16) { - return _('Username length must be between 4 and 16 characters.'); - } - - // Check for duplicate usernames - var otherSections = uci.sections('pppoe-user', 'user'); - for (var i = 0; i < otherSections.length; i++) { - if (section_id !== otherSections[i]['.name'] && otherSections[i]['username'] === value) { - return _('This username is already in use. Please choose a different one.'); - } - } - - return true; - }; - - // Service Name field (dropdown) - o = s.option(form.ListValue, 'servicename', _('Service Name')); - o.readonly = true; - o.modalonly = true; - o.value('*', _('Default')); - o.value('serviceA', 'Service A'); - o.value('serviceB', 'Service B'); - o.value('serviceC', 'Service C'); - - // Password field - o = s.option(form.Value, 'password', _('Password')); - o.placeholder = _('Required'); - o.password = true; - o.modalonly = true; - o.validate = function (section_id, value) { - // Validate the input value to ensure it's between 8 and 16 characters - if (value.length < 8 || value.length > 16) { - return _('Password must be between 8 and 16 characters.'); - } - return true; - }; - - var currentDate = new Date(); - var year = currentDate.getFullYear(); - var month = ('0' + (currentDate.getMonth() + 1)).slice(-2); - var day = ('0' + currentDate.getDate()).slice(-2); - var formattedDate = year + month + day; - - o.default = formattedDate.slice(0, 8); - o.rmempty = false; // Make the field required - - var currentDate = new Date(); - var year = currentDate.getFullYear(); - var month = ('0' + (currentDate.getMonth() + 1)).slice(-2); - var day = ('0' + currentDate.getDate()).slice(-2); - var formattedDate = year + month + day; - - o.default = formattedDate.slice(0, 8); - o.rmempty = false; // Make the field required - - // IP Address field (custom input with default value *) - o = s.option(form.Value, 'ipaddr', _('IP Address')); - o.placeholder = _('Required'); - o.default = '*'; - o.value('172.31.16.0/23', '172.31.16.0/23 Rules WAN1'); - o.value('172.31.26.0/23', '172.31.26.0/23 Rules WAN2'); - o.value('172.31.36.0/23', '172.31.36.0/23 Rules WAN3'); - o.value('172.31.46.0/23', '172.31.46.0/23 Rules WAN4'); - o.value('172.31.56.0/23', '172.31.56.0/23 Rules WAN5'); - o.value('172.31.66.0/23', '172.31.66.0/23 Rules WAN6'); - o.value('172.31.76.0/23', '172.31.76.0/23 Rules WAN7'); - o.value('172.31.86.0/23', '172.31.86.0/23 Rules WAN8'); - o.value('172.31.96.0/23', '172.31.96.0/23 Rules WAN9'); - o.value('*', _('Default')); - o.value('172.31.100.0/23', '172.31.100.0/23 Rules MAN0'); - o.value('172.31.110.0/23', '172.31.110.0/23 Rules MAN1'); - o.value('172.31.120.0/23', '172.31.120.0/23 Rules MAN2'); - o.value('172.31.130.0/23', '172.31.130.0/23 Rules MAN3'); - o.value('172.31.140.0/23', '172.31.140.0/23 Rules MAN4'); - o.value('172.31.150.0/23', '172.31.150.0/23 Rules MAN5'); - o.value('172.31.160.0/23', '172.31.160.0/23 Rules MAN6'); - o.value('172.31.170.0/23', '172.31.170.0/23 Rules MAN7'); - o.value('172.31.180.0/23', '172.31.180.0/23 Rules MAN8'); - o.value('172.31.190.0/23', '172.31.190.0/23 Rules MAN9'); - - // Enhanced validation for IP addresses and network segments - o.validate = function (section_id, value) { - // Regular expressions for valid IPv4, IPv6, and network segments - var ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/; - var ipv6Regex = /^[\da-fA-F]{1,4}(:[\da-fA-F]{1,4}){0,7}$/; - var networkSegmentRegex = /^(\d{1,3}\.){3}\d{1,3}\/(\d{1,2})$/; - - if (value === '*') { - return true; // Asterisk is allowed - } - - if (ipv4Regex.test(value)) { - // Validate IPv4 address - var parts = value.split('.'); - for (var i = 0; i < 4; i++) { - var part = parseInt(parts[i]); - if (part < 0 || part > 255) { - return _('Invalid IPv4 address. Each segment must be between 0 and 255.'); - } - } - // Check for duplicate IP addresses - var otherSections = uci.sections('pppoe-user', 'user'); - for (var i = 0; i < otherSections.length; i++) { - if (section_id !== otherSections[i]['.name'] && otherSections[i]['ipaddr'] === value) { - return _('This IP address is already in use by another user. Please choose a different one.'); - } - } - return true; - } - - if (ipv6Regex.test(value)) { - // Validate IPv6 address - var otherSections = uci.sections('pppoe-user', 'user'); - for (var i = 0; i < otherSections.length; i++) { - if (section_id !== otherSections[i]['.name'] && otherSections[i]['ipaddr'] === value) { - return _('This IP address is already in use by another user. Please choose a different one.'); - } - } - return true; - } - - if (networkSegmentRegex.test(value)) { - // Validate IP network segment - var subnetParts = value.split('/'); - var subnetSize = parseInt(subnetParts[1]); - - if (subnetSize < 0 || subnetSize > 32) { - return _('Invalid subnet size. It must be between 0 and 32.'); - } - - return true; - } - - // Invalid input, return an error message - return _('Invalid input. Please use "*" or a valid IPv4, IPv6 address, or IP network segment.'); - }; - - // Automatically generate an available IP address when a network segment is selected - o.cfgvalue = function (section_id) { - var selectedSegment = uci.get('pppoe-user', section_id, 'ipaddr'); - - // Add your new predefined network segment here - if (selectedSegment === '172.31.16.0/23' || - selectedSegment === '172.31.26.0/23' || - selectedSegment === '172.31.36.0/23' || - selectedSegment === '172.31.46.0/23' || - selectedSegment === '172.31.56.0/23' || - selectedSegment === '172.31.66.0/23' || - selectedSegment === '172.31.76.0/23' || - selectedSegment === '172.31.86.0/23' || - selectedSegment === '172.31.96.0/23' || - selectedSegment === '172.31.100.0/23' || - selectedSegment === '172.31.110.0/23' || - selectedSegment === '172.31.120.0/23' || - selectedSegment === '172.31.130.0/23' || - selectedSegment === '172.31.140.0/23' || - selectedSegment === '172.31.150.0/23' || - selectedSegment === '172.31.160.0/23' || - selectedSegment === '172.31.170.0/23' || - selectedSegment === '172.31.180.0/23' || - selectedSegment === '172.31.190.0/23') { - // Generate and assign an available IP address based on the selected network segment - var generatedIP = getAvailableIPAddress(selectedSegment); - - // Check if the generated IP address already exists in other sections - var otherSections = uci.sections('pppoe-user', 'user'); - for (var i = 0; i < otherSections.length; i++) { - if (section_id !== otherSections[i]['.name'] && otherSections[i]['ipaddr'] === generatedIP) { - generatedIP = getAvailableIPAddress(selectedSegment); // Regenerate if it's a duplicate - } - } - - uci.set('pppoe-user', section_id, 'ipaddr', generatedIP); - uci.save(); - return generatedIP; - } - return selectedSegment; - }; - - // Define a function to generate an available IP address based on the selected network segment - function getAvailableIPAddress(networkSegment) { - // Basic logic to generate an available IP address within the network segment - var segments = networkSegment.split('/'); - var baseIP = segments[0]; - var subnetSize = parseInt(segments[1]); - - // Generate a random host number within the subnet range (exclude network and broadcast) - var hostNumber = Math.floor(Math.random() * (Math.pow(2, 32 - subnetSize) - 2)) + 1; - - // Convert the host number to an IP address - var generatedIP = baseIP.split('.').map(function (part, index) { - return parseInt(part) + (hostNumber >> (8 * (3 - index)) & 255); - }).join('.'); - - return generatedIP; - }; - - // MAC Address field (dropdown) - o = s.option(form.Value, 'macaddr', _('MAC Address')); - o.modalonly = true; - o.placeholder = 'MAC Address'; - o.password = true; - o.readonly = true; - - // Package field (dropdown) - o = s.option(form.ListValue, 'package', _('Package')); - o.default = 'home'; - o.value('home', _('Home')); - o.value('office', _('Office')); - o.value('free', _('Free')); - o.value('test', _('Test')); - - // Enable QoS field (checkbox) - o = s.option(form.Flag, 'qos', _('QoS')); - o.modalonly = true; - o.default = '0'; - o.readonly = false; - o.rmempty = false; - - // Upload Speed field (dropdown) - var o = s.option(form.Value, 'urate', _('Upload Speed')); - o.modalonly = true; - o.placeholder = "1 to 10000 Mbps" - o.datatype = "range(1,10000)" - o.default = '15'; - o.depends('qos', '1'); // Show only when QoS is enabled - - // Download Speed field (dropdown) - var o = s.option(form.Value, 'drate', _('Download Speed')); - o.modalonly = true; - o.placeholder = "1 to 10000 Mbps" - o.datatype = "range(1,10000)" - o.default = '30'; - o.depends('qos', '1'); // Show only when QoS is enabled - - // Concurrent Connection Number Segment (dropdown menu) - var o = s.option(form.ListValue, 'connect', _('Connection Number')); - o.modalonly = true; - o.datatype = "range(128,1048576)" - o.default = '2048'; - o.value('128'); - o.value('256'); - o.value('512'); - o.value('1024'); - o.value('2048'); - o.value('4096'); - o.value('8192'); - o.value('16384'); - o.value('32768'); - o.value('65536'); - o.value('131072'); - o.value('262144'); - o.value('524288'); - o.value('1048576'); - o.depends('qos', '1'); // Show only when QoS is enabled - - // Opening Date field (read-only) - o = s.option(form.Value, 'opening', _('Opening Date')); - o.readonly = true; - // Automatically populate with the current date in 'YYYY-MM-DD' format - var currentDate = new Date(); - var year = currentDate.getFullYear(); - var month = ('0' + (currentDate.getMonth() + 1)).slice(-2); - var day = ('0' + currentDate.getDate()).slice(-2); - var formattedDate = year + '-' + month + '-' + day; - o.default = formattedDate; - - // Expiration Date field - o = s.option(form.Value, 'expires', _('Expiration Date')); - o.datatype = 'string'; - o.placeholder = 'YYYY-MM-DD'; - o.validate = function (section_id, value) { - // Validate the input value to match the format YYYY-MM-DD - if (!/^\d{4}-\d{2}-\d{2}$/.test(value)) { - return _('Invalid date format. Please use YYYY-MM-DD.'); - } - - // Split the date string into year, month, and day components - var parts = value.split('-'); - var year = parseInt(parts[0], 10); - var month = parseInt(parts[1], 10); - var day = parseInt(parts[2], 10); - - // Validate the year, month, and day values - if (isNaN(year) || isNaN(month) || isNaN(day)) { - return _('Invalid date values.'); - } - - if (month < 1 || month > 12) { - return _('Invalid month. Please use a value between 01 and 12.'); - } - - var daysInMonth = new Date(year, month, 0).getDate(); - if (day < 1 || day > daysInMonth) { - return _('Invalid day. Please use a value between 01 and ') + daysInMonth + '.'; - } - - return true; - }; - var currentDate = new Date(); - - // Calculate expiration dates based on the current day + 1/3/6/12 months - var oneMonthLater = new Date(currentDate); - oneMonthLater.setMonth(currentDate.getMonth() + 1); - var threeMonthsLater = new Date(currentDate); - threeMonthsLater.setMonth(currentDate.getMonth() + 3); - var sixMonthsLater = new Date(currentDate); - sixMonthsLater.setMonth(currentDate.getMonth() + 6); - var twelveMonthsLater = new Date(currentDate); - twelveMonthsLater.setMonth(currentDate.getMonth() + 12); - - // Convert calculated dates to YYYY-MM-DD format - function formatDate(date) { - var year = date.getFullYear(); - var month = (date.getMonth() + 1).toString().padStart(2, '0'); - var day = date.getDate().toString().padStart(2, '0'); - return year + '-' + month + '-' + day; - } - // Set the default value to three months later - o.default = formatDate(threeMonthsLater); - o.value(formatDate(oneMonthLater), formatDate(oneMonthLater) + ' ' + _('One Month')); - o.value(formatDate(threeMonthsLater), formatDate(threeMonthsLater) + ' ' + _('Three Months')); - o.value(formatDate(sixMonthsLater), formatDate(sixMonthsLater) + ' ' + _('Six Months')); - o.value(formatDate(twelveMonthsLater), formatDate(twelveMonthsLater) + ' ' + _('Twelve Months')); - - // Enable Connect field (checkbox) - o = s.option(form.Flag, 'more', _('Contact')); - o.rmempty = false; // Make the field required - o.modalonly = true; - o.default = '0'; - - // Address field (dropdown) - o = s.option(form.Value, 'address', _('Address')); - o.modalonly = true; - o.placeholder = 'User Address'; - o.depends('more', '1'); - - // E-mail field (dropdown) - o = s.option(form.DynamicList, 'mail', _('E-mail')); - o.modalonly = true; - o.placeholder = 'User Email'; - o.depends('more', '1'); - - // Phone field (dropdown) - o = s.option(form.DynamicList, 'phone', _('Telephone')); - o.modalonly = true; - o.placeholder = 'User Phone'; - o.depends('more', '1'); - - // GPS Location field (dropdown) - o = s.option(form.Value, 'gps', _('GPS')); - o.placeholder = 'ONT GPS Location'; - o.modalonly = true; - o.depends('more', '1'); - - o = s.option(form.TextValue, 'notes', _('Notes'), _('')); - o.modalonly = true; - o.optional = true; - o.depends('more', '1'); - - // Agent field (dropdown) - o = s.option(form.Value, 'agent', _('Agent')); - o.modalonly = true; - o.readonly = true; - - // Enable ONT field (checkbox) - o = s.option(form.Flag, 'ont', _('ONT')); - o.rmempty = false; // Make the field required - o.modalonly = true; - o.default = '0'; - - // OLT field (dropdown) - var o = s.option(form.Value, 'olt', _('OLT')); - o.modalonly = true; - o.value('1', 'OLT 1'); - o.value('2', 'OLT 2'); - o.value('3', 'OLT 3'); - o.value('4', 'OLT 4'); - o.value('5', 'OLT 5'); - o.value('6', 'OLT 6'); - o.value('7', 'OLT 7'); - o.value('8', 'OLT 8'); - o.value('9', 'OLT 9'); - o.value('10', 'OLT 10'); - o.value('11', 'OLT 11'); - o.value('12', 'OLT 12'); - o.value('13', 'OLT 13'); - o.value('14', 'OLT 14'); - o.value('15', 'OLT 15'); - o.value('16', 'OLT 16'); - o.value('17', 'OLT 17'); - o.value('18', 'OLT 18'); - o.value('19', 'OLT 19'); - o.value('20', 'OLT 20'); - o.depends('ont', '1'); - - // PON field (dropdown) - var o = s.option(form.Value, 'pon', _('PON')); - o.modalonly = true; - o.value('1', 'PON 1'); - o.value('2', 'PON 2'); - o.value('3', 'PON 3'); - o.value('4', 'PON 4'); - o.value('5', 'PON 5'); - o.value('6', 'PON 6'); - o.value('7', 'PON 7'); - o.value('8', 'PON 8'); - o.value('9', 'PON 9'); - o.value('10', 'PON 10'); - o.value('11', 'PON 11'); - o.value('12', 'PON 12'); - o.value('13', 'PON 13'); - o.value('14', 'PON 14'); - o.value('15', 'PON 15'); - o.value('16', 'PON 16'); - o.depends('ont', '1'); - - // Serial Number field (dropdown) - o = s.option(form.Value, 'sn', _('S/N')); - o.modalonly = true; - o.placeholder = 'ONT Serial Number'; - o.depends('ont', '1'); - - // Submit button - return m.render(); - }, - handleSave: null, - handleSaveApply: null, - handleReset: null -}); diff --git a/luci-app-pppoe-user/po/templates/pppoe-user.pot b/luci-app-pppoe-user/po/templates/pppoe-user.pot deleted file mode 100644 index 44ca0c50..00000000 --- a/luci-app-pppoe-user/po/templates/pppoe-user.pot +++ /dev/null @@ -1,170 +0,0 @@ -msgid "" -msgstr "Content-Type: text/plain; charset=UTF-8" - -msgid "Management" -msgstr "" - -msgid "User Manager" -msgstr "" - -msgid "New Users" -msgstr "" - -msgid "User List" -msgstr "" - -msgid "ONU List" -msgstr "" - -msgid "User Number" -msgstr "" - -msgid "Enabled" -msgstr "" - -msgid "User Name" -msgstr "" - -msgid "Account" -msgstr "" - -msgid "This username is already in use. Please choose a different one." -msgstr "" - -msgid "Service Name" -msgstr "" - -msgid "Password" -msgstr "" - -msgid "Password must be between 8 and 16 characters." -msgstr "" - -msgid "IP Address" -msgstr "" - -msgid "Invalid IPv4 address. Each segment must be between 0 and 255." -msgstr "" - -msgid "This IP address is already in use by another user. Please choose a different one." -msgstr "" - -msgid "Invalid subnet size. It must be between 0 and 32." -msgstr "" - -msgid "Invalid input. Please use "*" or a valid IPv4, IPv6 address, or IP network segment." -msgstr "" - -msgid "Package" -msgstr "" - -msgid "Speed" -msgstr "" - -msgid "QoS" -msgstr "" - -msgid "Upload Speed" -msgstr "" - -msgid "Download Speed" -msgstr "" - -msgid "Speed Unit" -msgstr "" - -msgid "Connection Number" -msgstr "" - -msgid "Queuing Rules" -msgstr "" - -msgid "Queue Script" -msgstr "" - -msgid "Link Layer" -msgstr "" - -msgid "Overhead Bytes" -msgstr "" - -msgid "Debug Logging" -msgstr "" - -msgid "Opening Date" -msgstr "" - -msgid "Validity Period" -msgstr "" - -msgid "Expiration Date" -msgstr "" - -msgid "Invalid date format. Please use YYYY-MM-DD." -msgstr "" - -msgid "Agent" -msgstr "" - -msgid "Default" -msgstr "" - -msgid "Home" -msgstr "" - -msgid "Office" -msgstr "" - -msgid "Free" -msgstr "" - -msgid "Test" -msgstr "" - -msgid "One Month" -msgstr "" - -msgid "Three Months" -msgstr "" - -msgid "Six Months" -msgstr "" - -msgid "Twelve Months" -msgstr "" - -msgid "ONU Manager" -msgstr "" - -msgid "ONT" -msgstr "" - -msgid "ONT Serial Number" -msgstr "" - -msgid "Contact" -msgstr "" - -msgid "E-mail" -msgstr "" - -msgid "Telephone" -msgstr "" - -msgid "User Status" -msgstr "" - -msgid "Online User" -msgstr "" - -msgid "Up Time" -msgstr "" - -msgid "Renewal Date" -msgstr "" - -msgid "Process ID" -msgstr "" - -msgid "Forced Offline" -msgstr "" diff --git a/luci-app-pppoe-user/po/zh-cn b/luci-app-pppoe-user/po/zh-cn deleted file mode 120000 index 8d69574d..00000000 --- a/luci-app-pppoe-user/po/zh-cn +++ /dev/null @@ -1 +0,0 @@ -zh_Hans \ No newline at end of file diff --git a/luci-app-pppoe-user/po/zh_Hans/pppoe-user.po b/luci-app-pppoe-user/po/zh_Hans/pppoe-user.po deleted file mode 100644 index ba1e9ab3..00000000 --- a/luci-app-pppoe-user/po/zh_Hans/pppoe-user.po +++ /dev/null @@ -1,167 +0,0 @@ -msgid "Management" -msgstr "管理" - -msgid "User Manager" -msgstr "用户管理" - -msgid "New Users" -msgstr "新增用户" - -msgid "User List" -msgstr "用户列表" - -msgid "ONU List" -msgstr "光猫列表" - -msgid "User Number" -msgstr "用户数" - -msgid "Enabled" -msgstr "启用" - -msgid "User Name" -msgstr "用户名" - -msgid "Account" -msgstr "账号" - -msgid "This username is already in use. Please choose a different one." -msgstr "该用户名已被使用。 请选择一个不同的。" - -msgid "Service Name" -msgstr "服务名称" - -msgid "Password" -msgstr "密码" - -msgid "Password must be between 8 and 16 characters." -msgstr "密码必须介于 8 到 16 个字符之间。" - -msgid "IP Address" -msgstr "IP 地址" - -msgid "Invalid IPv4 address. Each segment must be between 0 and 255." -msgstr "IPv4 地址无效。 每个段必须介于 0 到 255 之间。" - -msgid "This IP address is already in use by another user. Please choose a different one." -msgstr "该 IP 地址已被其他用户使用。 请选择一个不同的。" - -msgid "Invalid subnet size. It must be between 0 and 32." -msgstr "子网大小无效。 它必须介于 0 和 32 之间。" - -msgid "Invalid input. Please use "*" or a valid IPv4, IPv6 address, or IP network segment." -msgstr "输入无效。 请使用“*”或有效的 IPv4、IPv6 地址或 IP 网段。" - -msgid "Package" -msgstr "套餐" - -msgid "Speed" -msgstr "网速" - -msgid "QoS" -msgstr "限速" - -msgid "Upload Speed" -msgstr "上传速度" - -msgid "Download Speed" -msgstr "下载速度" - -msgid "Speed Unit" -msgstr "速度单位" - -msgid "Connection Number" -msgstr "连接数" - -msgid "Queuing Rules" -msgstr "队列规则" - -msgid "Queue Script" -msgstr "队列脚本" - -msgid "Link Layer" -msgstr "链路层" - -msgid "Overhead Bytes" -msgstr "开销字节" - -msgid "Debug Logging" -msgstr "调试日志" - -msgid "Opening Date" -msgstr "开通日期" - -msgid "Validity Period" -msgstr "有效期" - -msgid "Expiration Date" -msgstr "截止日期" - -msgid "Invalid date format. Please use YYYY-MM-DD." -msgstr "日期格式无效。 请使用 YYYY-MM-DD。" - -msgid "Agent" -msgstr "代理人" - -msgid "Default" -msgstr "默认" - -msgid "Home" -msgstr "家" - -msgid "Office" -msgstr "办公" - -msgid "Free" -msgstr "免费" - -msgid "Test" -msgstr "测试" - -msgid "One Month" -msgstr "一个月" - -msgid "Three Months" -msgstr "三个月" - -msgid "Six Months" -msgstr "半年" - -msgid "Twelve Months" -msgstr "一年" - -msgid "ONU Manager" -msgstr "光猫管理" - -msgid "ONT" -msgstr "光猫绑定" - -msgid "ONT Serial Number" -msgstr "光猫序列号" - -msgid "Contact" -msgstr "联系方式" - -msgid "E-mail" -msgstr "电子邮箱" - -msgid "Telephone" -msgstr "电话" - -msgid "User Status" -msgstr "用户状态" - -msgid "Online User" -msgstr "在线用户" - -msgid "Up Time" -msgstr "上线时间" - -msgid "Renewal Date" -msgstr "续订日期" - -msgid "Process ID" -msgstr "进程 ID" - -msgid "Forced Offline" -msgstr "强制下线" diff --git a/luci-app-pppoe-user/root/etc/config/pppoe-user b/luci-app-pppoe-user/root/etc/config/pppoe-user deleted file mode 100644 index 490a4c70..00000000 --- a/luci-app-pppoe-user/root/etc/config/pppoe-user +++ /dev/null @@ -1,13 +0,0 @@ - -config user - option enabled '1' - option username 'guest' - option servicename '*' - option password '12345678' - option ipaddr '*' - option package 'home' - option qos '1' - option urate '15' - option drate '30' - option connect '1024' - diff --git a/luci-app-pppoe-user/root/etc/hotplug.d/iface/30-interface b/luci-app-pppoe-user/root/etc/hotplug.d/iface/30-interface deleted file mode 100644 index fe27f319..00000000 --- a/luci-app-pppoe-user/root/etc/hotplug.d/iface/30-interface +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -. /lib/functions.sh - -PPPOE_TIME="$(date "+%Y-%m-%d_%H:%M:%S")" -GATEWAY="$(uci get network."$INTERFACE".gateway)" -PING="$(ping "$GATEWAY" -I "$DEVICE" -c 5 | awk '{ print strftime("%Y-%m-%d %H:%M:%S",systime())"\t" $0; fflush() }' | grep -E 'rtt|round-trip' | cut -d "=" -f2)" - -echo "$PPPOE_TIME Track Device=$DEVICE, Interface=$INTERFACE, Gateway=$GATEWAY, Ping=$PING, Action=$ACTION" >> /var/pppoe-user/log/interface.log diff --git a/luci-app-pppoe-user/root/etc/init.d/pppoe-user b/luci-app-pppoe-user/root/etc/init.d/pppoe-user deleted file mode 100755 index 062c9637..00000000 --- a/luci-app-pppoe-user/root/etc/init.d/pppoe-user +++ /dev/null @@ -1,180 +0,0 @@ -#!/bin/sh /etc/rc.common -# Copyright (C) 2024-2026 OpenWrt.org -# Licensed under GPL v2 - -START=90 -STOP=10 - -USE_PROCD=1 -PROG=/usr/sbin/pppoe-server -UBUS_HELPER=/usr/share/ucode/pppoe-ubus.uc -UCODE_BIN=/usr/bin/ucode - -SPEED_LIMIT_SWITCH=1 -CHAP_SECRETS=/etc/ppp/chap-secrets -BACKUP_DIR=/var/pppoe-user/backup -LOG_DIR=/var/pppoe-user/log -SESSION_DIR=/var/etc/pppoe-user/session - -# 初始化目录 -init_dirs() { - mkdir -p "$BACKUP_DIR" - mkdir -p "$LOG_DIR" - mkdir -p "$LOG_DIR/userinfo" - mkdir -p "$SESSION_DIR" - mkdir -p /var/lock -} - -# 使用 ucode 进行日期比较和状态检查 (更高效且不易出错) -check_expiration_and_build_secrets() { - local current_date - current_date=$(date +"%Y-%m-%d") - - # 清空并重建 chap-secrets - : > "$CHAP_SECRETS" - - # 遍历 UCI 配置 - config_load pppoe-user - - config_foreach setup_user "$current_date" -} - -# 回调函数:处理每个用户配置 -# 参数 1: cfg_name, 参数 2: current_date -setup_user() { - local cfg="$1" - local today="$2" - local enabled username servicename password ipaddr expires - - config_get_bool enabled "$cfg" enabled 0 - config_get username "$cfg" username - config_get servicename "$cfg" servicename - config_get password "$cfg" password - config_get ipaddr "$cfg" ipaddr - config_get expires "$cfg" expires - - # 默认 servicename 为 * - [ -z "$servicename" ] && servicename="*" - - # 检查过期 - if [ "$enabled" -eq 1 ] && [ -n "$expires" ] && [ "$expires" = "$today" ]; then - logger -t pppoe-user "User $username expired today ($today). Disabling." - uci set pppoe-user."$cfg".enabled=0 - uci commit pppoe-user - enabled=0 - fi - - # 如果启用且未过期,写入 chap-secrets - if [ "$enabled" -eq 1 ]; then - # 格式: user service secret IP - echo "$username $servicename $password $ipaddr" >> "$CHAP_SECRETS" - fi -} - -# 管理 Crontab 任务 -manage_cron() { - local cron_cmd_start="59 6 * * * /etc/init.d/pppoe-user start" - local cron_cmd_backup="59 23 * * * cp -f /etc/config/pppoe-user $BACKUP_DIR/pppoe-user.\$(date +\%Y\%m\%d).bak" - - # 移除旧的任务(防止重复) - crontab -u root -l 2>/dev/null | grep -v "/etc/init.d/pppoe-user start" | grep -v "cp -f /etc/config/pppoe-user" | crontab -u root - - - # 添加新任务 - (crontab -u root -l 2>/dev/null; echo "$cron_cmd_start"; echo "$cron_cmd_backup") | sort -u | crontab -u root - -} - -# 配置 nftables 限速表 -setup_nft() { - # 检查表是否存在,存在则先删除以保证幂等性 - nft list table inet pppoe >/dev/null 2>&1 && nft delete table inet pppoe - - nft add table inet pppoe - nft add chain inet pppoe upload { type filter hook prerouting priority filter\; policy accept\; } - nft add chain inet pppoe download { type filter hook postrouting priority filter\; policy accept\; } - - # 更新防火墙区域配置以包含 ppp 接口 - local zone_device - zone_device=$(uci get firewall.@zone[0].device 2>/dev/null) - if [ -z "$(echo "$zone_device" | grep 'ppp+')" ]; then - uci add_list firewall.@zone[0].device='ppp+' - uci commit firewall - # 注意:这里不重启 firewall,以免断开现有连接,nft 规则即时生效 - fi -} - -cleanup_nft() { - nft list table inet pppoe >/dev/null 2>&1 && nft delete table inet pppoe -} - -# 启动 ucode ubus 辅助服务 -start_ubus_helper() { - if [ -x "$UCODE_BIN" ] && [ -f "$UBUS_HELPER" ]; then - # 检查是否已在运行 - if ! pgrep -f "ucode.*pppoe-ubus.uc" >/dev/null; then - logger -t pppoe-user "Starting ubus helper service" - $UCODE_BIN $UBUS_HELPER & - disown - fi - else - logger -t pppoe-user "Warning: ucode helper not found or not executable. LuCI kill function may fail." - fi -} - -stop_ubus_helper() { - pkill -f "ucode.*pppoe-ubus.uc" -} - -start_service() { - init_dirs - - logger -t pppoe-user "Starting PPPoE User Management Service" - - # 备份旧的 chap-secrets - [ -f "$CHAP_SECRETS" ] && cp -f "$CHAP_SECRETS" /etc/ppp/lasttime-chap-secrets - - # 生成新的 chap-secrets 并检查过期 - check_expiration_and_build_secrets - - # 设置权限 - chmod 600 "$CHAP_SECRETS" - - # 配置定时任务 - manage_cron - - # 配置限速 - if [ "$SPEED_LIMIT_SWITCH" = "1" ]; then - setup_nft - else - cleanup_nft - fi - - # 启动 ubus 辅助进程 (供 LuCI JS 调用) - start_ubus_helper - - # 如果是作为服务运行,不需要保持前台,因为主要工作是生成配置和规则 - # 真正的 PPPoE 服务由 pppoe-server 守护进程管理 -} - -stop_service() { - logger -t pppoe-user "Stopping PPPoE User Management Service" - - stop_ubus_helper - cleanup_nft - - # 可选:清除 chap-secrets (通常不建议,因为重启后需要,但在 stop 时清理可确保安全) - # : > "$CHAP_SECRETS" -} - -reload_service() { - stop_service - start_service -} - -# 兼容旧版 procd 的 stop 行为 -stop() { - stop_service -} - -service_triggers() { - procd_add_reload_trigger "pppoe-user" -} diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-down b/luci-app-pppoe-user/root/etc/ppp/ip-down deleted file mode 100755 index 7448a641..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-down +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -# This script is run by the pppd _after_ the link is brought down. -# It should be used to delete routes, unset IP addresses, etc. - -# Check if the required number of arguments is provided -if [ $# -ne 5 ]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -# Reset the PATH variable -PATH=/usr/sbin:/sbin:/usr/bin:/bin -export PATH - -# Log the start of the script -logger "Starting ip-down script for interface $1 with local IP $4 and peer IP $5" - -# Define the directory containing additional scripts -IP_DOWN_D_DIR="/etc/ppp/ip-down.d" - -# Check if the directory exists -if [ ! -d "$IP_DOWN_D_DIR" ]; then - echo "Directory $IP_DOWN_D_DIR does not exist." >&2 - exit 1 -fi - -# Loop through all files in the ip-down.d directory and execute them if they are executable -for script in "$IP_DOWN_D_DIR"/*; do - if [ -x "$script" ]; then - "$script" "$@" || { - echo "Error executing $script" >&2 - exit 1 - } - fi -done - -# Log the successful completion of the script -logger "Completed ip-down script for interface $1" - -exit 0 diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-down.d/offline-users b/luci-app-pppoe-user/root/etc/ppp/ip-down.d/offline-users deleted file mode 100755 index 622c09d1..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-down.d/offline-users +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -# -# This script is run by pppd _after_ the link is brought down. -# It should be used to delete routes, unset IP addresses, etc. -# -# This script is called with the following arguments: -# Arg Name Example -# $1 Interface name ppp0 -# $2 The tty ttyS1 -# $3 The link speed 38400 -# $4 Local IP number 12.34.56.78 -# $5 Peer IP number 12.34.56.99 -# - -# Reset the PATH environment variable -PATH=/usr/sbin:/sbin:/usr/bin:/bin -export PATH - -# Get the current date and time -QUIT_TIME="$(date "+%Y-%m-%d_%H:%M:%S")" - -# Extract username, interface name, and peer IP address from arguments -USERNAME="${PEERNAME}" -IFACE="${1}" -TTY="${2}" -PEERIP="${5}" - -# Paths and Configuration -USER_LOG="/var/pppoe-user/log/userinfo" -USER_LOG_FILE="${USER_LOG}/${USERNAME}.log" -USER_CONFIG="pppoe-user" -USER_CFGID="$(uci show ${USER_CONFIG} | grep "${USERNAME}" | cut -d '.' -sf 2)" -USER_CONNECT="$(uci get ${USER_CONFIG}.${USER_CFGID}.connect)" -SESSION_PATH="/var/etc/pppoe-user/session" - -# Remove the session file -rm -f "${SESSION_PATH}/${USERNAME}.${IFACE}" - -# Log the disconnection details -echo "${QUIT_TIME} ${USERNAME} Offline Interface: ${IFACE} IP: ${PEERIP}" >> "${USER_LOG_FILE}" -echo "Connect time: ${CONNECT_TIME} minutes" >> "${USER_LOG_FILE}" -echo "Sent: ${BYTES_SENT} bytes" >> "${USER_LOG_FILE}" -echo "Received: ${BYTES_RCVD} bytes" >> "${USER_LOG_FILE}" - -# Calculate and log the sum and average speed -sum_bytes=$((${BYTES_SENT} + ${BYTES_RCVD})) -sum=$(echo "scale=2;${sum_bytes}/1024/1024" | bc) -echo "Bytes sum: ${sum} MB" >> "${USER_LOG_FILE}" -ave=$(echo "scale=2;${sum_bytes}/1024/${CONNECT_TIME}" | bc) -echo "Average speed: ${ave} KB/s" >> "${USER_LOG_FILE}" - -# Add an empty line for separation in the log file -echo >> "${USER_LOG_FILE}" - -# Log the execution -logger "${QUIT_TIME} ${PEERNAME} ${PEERIP} OFFLINE-USERS >>>>>> The script has been executed!" - -exit 0 diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-down.d/speed-limit b/luci-app-pppoe-user/root/etc/ppp/ip-down.d/speed-limit deleted file mode 100755 index 9fe4e931..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-down.d/speed-limit +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh -( - flock -n 200 || exit 1 - - # The environment is cleared before executing this script - PATH=/usr/sbin:/sbin:/usr/bin:/bin - export PATH - - QUIT_TIME="$(date "+%Y-%m-%d_%H:%M:%S")" - USERNAME="${PEERNAME}" - PEERIP="${5}" - - USER_CONFIG="pppoe-user" - USER_CFGID="$(uci show ${USER_CONFIG} | grep "${USERNAME}" | cut -d '.' -f 2)" - TABLE="pppoe" - - # Define chains - CHAINS="upload download" - - # Loop through each chain and delete all rules matching the IP - for CHAIN in ${CHAINS}; do - # Get all rule handles associated with the IP in the current chain - RULE_HANDLES="$(nft -a list chain inet ${TABLE} ${CHAIN} | grep "${PEERIP}" | awk '{print $NF}')" - - if [ -n "${RULE_HANDLES}" ]; then - for HANDLE in ${RULE_HANDLES}; do - nft delete rule inet ${TABLE} ${CHAIN} handle "${HANDLE}" || { - logger "${QUIT_TIME} ERROR: Failed to delete rule handle ${HANDLE} in chain ${CHAIN} for ${USERNAME} ${PEERIP}" - exit 1 - } - done - else - logger "${QUIT_TIME} WARNING: No rules found for ${USERNAME} ${PEERIP} in chain ${CHAIN}" - fi - done - - exit 0 - -) 200>/var/lock/ipdown.lock diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-up b/luci-app-pppoe-user/root/etc/ppp/ip-up deleted file mode 100755 index b5302cb5..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-up +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/sh - -# This script is run by the pppd after the link is established. -# It should be used to add routes, set IP address, run the mailq, etc. - -# Check if the required number of arguments is provided -if [ $# -ne 5 ]; then - echo "Usage: $0 " >&2 - exit 1 -fi - -# Reset the PATH variable -PATH=/usr/sbin:/sbin:/usr/bin:/bin -export PATH - -# Log the start of the script -logger "Starting ip-up script for interface $1 with local IP $4 and peer IP $5" - -# Define the directory containing additional scripts -IP_UP_D_DIR="/etc/ppp/ip-up.d" - -# Check if the directory exists -if [ ! -d "$IP_UP_D_DIR" ]; then - echo "Directory $IP_UP_D_DIR does not exist." >&2 - exit 1 -fi - -# Loop through all files in the ip-up.d directory and execute them if they are executable -for script in "$IP_UP_D_DIR"/*; do - if [ -x "$script" ]; then - "$script" "$@" || { - echo "Error executing $script" >&2 - exit 1 - } - fi -done - -# Log the successful completion of the script -logger "Completed ip-up script for interface $1" - -exit 0 diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-up.d/online-users b/luci-app-pppoe-user/root/etc/ppp/ip-up.d/online-users deleted file mode 100755 index 41ef74eb..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-up.d/online-users +++ /dev/null @@ -1,87 +0,0 @@ -#!/bin/sh -# -# This script is run by pppd after the link is established. -# It is used to add routes, set IP address, run mailq, etc. -# -# This script is called with the following arguments: -# Arg Name Example -# $1 Interface name ppp0 -# $2 The tty ttyS1 -# $3 The link speed 38400 -# $4 Local IP number 12.34.56.78 -# $5 Peer IP number 12.34.56.99 -# - -# Reset the PATH environment variable -PATH=/usr/sbin:/sbin:/usr/bin:/bin -export PATH - -LOGIN_TIME=$(date "+%Y-%m-%d_%H:%M:%S") -USERNAME="${PEERNAME}" -IFACE="${1}" -TTY="${2}" -PEERIP="${5}" - -USER_LOG="/var/pppoe-user/log/userinfo" -USER_LOG_FILE="${USER_LOG}/${USERNAME}.log" -USER_CONFIG="pppoe-user" -USER_CFGID="$(uci show ${USER_CONFIG} | grep "${USERNAME}" | cut -d '.' -sf 2)" -SERVIC_NAME="$(uci get ${USER_CONFIG}.${USER_CFGID}.servicename)" -USER_PACKAGE="$(uci get ${USER_CONFIG}.${USER_CFGID}.package)" -USER_QOS="$(uci get ${USER_CONFIG}.${USER_CFGID}.qos)" -USER_UPLOAD="$(uci get ${USER_CONFIG}.${USER_CFGID}.urate)" -USER_DOWNLOAD="$(uci get ${USER_CONFIG}.${USER_CFGID}.drate)" -USER_CONNECT="$(uci get ${USER_CONFIG}.${USER_CFGID}.connect)" -RENEWAL_DATE="$(uci get ${USER_CONFIG}.${USER_CFGID}.expires)" - -CONFIG_PATH="/var/etc/pppoe-user" -SESSION_PATH="${CONFIG_PATH}/session" - -PID="$(cat /var/run/pppd/${IFACE}.pid 2>/dev/null)" -MAC="$(ps -w | grep pppd | grep -v 'grep' | grep -h -m 1 "${PID}" | awk '{print $10}' | cut -d : -f 2,2-7)" - -mkdir -p "${USER_LOG}" -mkdir -p "${SESSION_PATH}" - -# Write session information in JSON format -cat <<-EOF > "${SESSION_PATH}/${USERNAME}.${IFACE}" -{ - "username": "${USERNAME}", - "mac": "${MAC}", - "interface": "${IFACE}", - "tty": "${TTY}", - "speed": "${SPEED}", - "ip": "${PEERIP}", - "servicename": "${SERVIC_NAME}", - "package": "${USER_PACKAGE}", - "connect": "${USER_CONNECT}", - "updated": "${RENEWAL_DATE}", - "uptime": "${LOGIN_TIME}", - "pid": "${PID}" -} -EOF - -# Find and kill previous PPP sessions for the same user -cfgid=$(uci show ${USER_CONFIG} | grep "@user" | grep ".username='${USERNAME}'" | cut -d '.' -sf 2) -if [ -n "$cfgid" ]; then - HAS_LOGIN=$(ls "${SESSION_PATH}" | grep "^${USERNAME}\.ppp" | grep -v "${IFACE}") - if [ -n "$HAS_LOGIN" ]; then - KO_IFACE=$(echo "$HAS_LOGIN" | awk -F '.' '{print $2}') - KO_PID=$(cat "/var/run/${KO_IFACE}.pid" 2>/dev/null) - [ -n "$KO_PID" ] && kill -9 "$KO_PID" >/dev/null 2>&1 - rm -f "${SESSION_PATH}/${HAS_LOGIN}" - rm -f "/var/run/${KO_IFACE}.pid" - fi -fi - -# Update the MAC address in the user's configuration -uci set "${USER_CONFIG}.${USER_CFGID}.macaddr=${MAC}" -uci commit "${USER_CONFIG}" - -# Log the connection details -echo "${LOGIN_TIME} ${USERNAME} Online PID: ${PID} Interface: ${IFACE} IP: ${PEERIP} MAC: ${MAC}" >> "${USER_LOG_FILE}" -echo >> "${USER_LOG_FILE}" - -logger "${LOGIN_TIME} ${PEERNAME} ${PEERIP} ONLINE-USERS >>>>>> The script has been executed!" - -exit 0 diff --git a/luci-app-pppoe-user/root/etc/ppp/ip-up.d/speed-limit b/luci-app-pppoe-user/root/etc/ppp/ip-up.d/speed-limit deleted file mode 100755 index 7bb26c96..00000000 --- a/luci-app-pppoe-user/root/etc/ppp/ip-up.d/speed-limit +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/sh -( - flock -n 200 || exit 1 - - # Environment variable settings - PATH=/usr/sbin:/sbin:/usr/bin:/bin - export PATH - - LOGIN_TIME="$(date "+%Y-%m-%d_%H:%M:%S")" - USERNAME="${PEERNAME}" - PEERIP="${5}" - - USER_CONFIG="pppoe-user" - USER_CFGID="$(uci show ${USER_CONFIG} | grep "${USERNAME}" | cut -d '.' -f 2)" - - # Convert Mbps to KBytes - USER_QOS="$(uci get ${USER_CONFIG}.${USER_CFGID}.qos 2>/dev/null)" - USER_UPLOAD="$(($(uci get ${USER_CONFIG}.${USER_CFGID}.urate 2>/dev/null) * 125))" - USER_DOWNLOAD="$(($(uci get ${USER_CONFIG}.${USER_CFGID}.drate 2>/dev/null) * 125))" - UPLOAD_BURST="$((USER_UPLOAD / 10))" - DOWNLOAD_BURST="$((USER_DOWNLOAD / 10))" - USER_CONNECT="$(uci get ${USER_CONFIG}.${USER_CFGID}.connect 2>/dev/null)" - - # Ensure that the obtained values are valid - if [ -z "${USER_QOS}" ] || [ -z "${USER_UPLOAD}" ] || [ -z "${USER_DOWNLOAD}" ] || [ -z "${USER_CONNECT}" ]; then - logger "${LOGIN_TIME} ERROR: Failed to get user config for (${USERNAME}) (${PEERIP})" - exit 1 - fi - - UP="upload" - DOWN="download" - - # Add traffic control rules - if [ "${USER_QOS}" = "1" ]; then - # Ensure rules are inserted in the correct order - - # Upload chain - nft insert rule inet pppoe ${UP} ip saddr "${PEERIP}" ct count over "${USER_CONNECT}" drop - nft insert rule inet pppoe ${UP} ip saddr "${PEERIP}" ct state new limit rate "${USER_CONNECT}"/minute accept - nft insert rule inet pppoe ${UP} ip saddr "${PEERIP}" limit rate over "${USER_UPLOAD}" kbytes/second burst "${UPLOAD_BURST}" kbytes counter drop - if [ $? -ne 0 ]; then - logger "${LOGIN_TIME} ERROR: Failed to insert upload rules (${USERNAME}) (${PEERIP})" - exit 1 - fi - - # Download chain - nft insert rule inet pppoe ${DOWN} ip daddr "${PEERIP}" ct count over "${USER_CONNECT}" drop - nft insert rule inet pppoe ${DOWN} ip daddr "${PEERIP}" ct state new limit rate "${USER_CONNECT}"/minute accept - nft insert rule inet pppoe ${DOWN} ip daddr "${PEERIP}" limit rate over "${USER_DOWNLOAD}" kbytes/second burst "${DOWNLOAD_BURST}" kbytes counter drop - if [ $? -ne 0 ]; then - logger "${LOGIN_TIME} ERROR: Failed to insert download rules (${USERNAME}) (${PEERIP})" - exit 1 - fi - fi - - exit 0 - -) 200>/var/lock/ipup.lock diff --git a/luci-app-pppoe-user/root/etc/uci-defaults/pppoe-user b/luci-app-pppoe-user/root/etc/uci-defaults/pppoe-user deleted file mode 100644 index a62bf45e..00000000 --- a/luci-app-pppoe-user/root/etc/uci-defaults/pppoe-user +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -[ ! -f "/usr/share/ucitrack/luci-app-pppoe-user.json" ] && { - cat > /usr/share/ucitrack/luci-app-pppoe-user.json << EEOF -{ - "config": "pppoe-user", - "init": "pppoe-user" -} -EEOF -} - -uci -q batch <<-EOF >/dev/null - delete ucitrack.@pppoe-user[-1] - add ucitrack pppoe-user - set ucitrack.@pppoe-user[-1].init=pppoe-user - commit ucitrack -EOF - -chmod 600 /etc/config/pppoe-user -chmod 755 /etc/init.d/pppoe-user -chmod 755 /etc/ppp/ip-up /etc/ppp/ip-down -chmod 755 /etc/ppp/auth-up /etc/ppp/auth-down -chmod +x /etc/ppp/ip-up.d/* /etc/ppp/ip-down.d/* - -rm -rf /tmp/luci-*cache -exit 0 diff --git a/luci-app-pppoe-user/root/usr/share/luci/menu.d/luci-app-pppoe-user.json b/luci-app-pppoe-user/root/usr/share/luci/menu.d/luci-app-pppoe-user.json deleted file mode 100644 index e0ef4e49..00000000 --- a/luci-app-pppoe-user/root/usr/share/luci/menu.d/luci-app-pppoe-user.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "admin/pppoe-user": { - "title": "Management", - "order": 60, - "action": { - "type": "alias", - }, - "depends": { - "acl": [ "luci-app-pppoe-user" ], - } - }, - - "admin/pppoe-user/usermanager": { - "title": "User Manager", - "order": 1, - "action": { - "type": "view", - "path": "pppoe-user/user", - } - }, - - "admin/pppoe-user/onumanager": { - "title": "ONU Manager", - "order": 2, - "action": { - "type": "view", - "path": "pppoe-user/onu", - } - }, - - "admin/status/userstatus": { - "title": "User Status", - "order": 88, - "action": { - "type": "alias", - "path": "admin/status/userstatus/onlineuser", - "post": { "cbi.submit": true } - }, - "depends": { - "acl": [ "luci-app-pppoe-user" ], - "uci": { "pppoe-user": true } - } - }, - - "admin/status/userstatus/onlineuser": { - "title": "Online User", - "order": 1, - "action": { - "type": "form", - "path": "pppoe-user/onlineuser", - } - }, - - "admin/status/userstatus/downtimeuser": { - "title": "Downtime User", - "order": 2, - "action": { - "type": "form", - "path": "pppoe-user/downtimeuser", - } - }, - - "admin/status/userstatus/interface": { - "title": "Interface Monitor", - "order": 3, - "action": { - "type": "form", - "path": "pppoe-user/interface", - } - } -} diff --git a/luci-app-pppoe-user/root/usr/share/rpcd/acl.d/luci-app-pppoe-user.json b/luci-app-pppoe-user/root/usr/share/rpcd/acl.d/luci-app-pppoe-user.json deleted file mode 100644 index 2940bba9..00000000 --- a/luci-app-pppoe-user/root/usr/share/rpcd/acl.d/luci-app-pppoe-user.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "luci-app-pppoe-user": { - "description": "Grant access to pppoe-user", - "read": { - "uci": [ "pppoe-user" ], - "file": { - "/var/etc/pppoe-user/session/*.json": [ "read" ], - "/var/pppoe-user/log/interface.log": [ "read" ], - "/proc/net/dev": [ "read" ] - } - }, - "write": { - "uci": [ "pppoe-user" ], - "exec": { - "/bin/kill": [ "arg1" ], - "/usr/bin/unlink": [ "arg1" ] - } - } - } -} diff --git a/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-ubus.uc b/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-ubus.uc deleted file mode 100644 index 351dad80..00000000 --- a/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-ubus.uc +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/ucode -import { ubus } from 'ubus'; -import { unlink } from 'fs'; - -let conn = ubus.connect(); -if (!conn) exit(1); - -conn.add({ - name: 'pppoe.user', - methods: { - kill: { - args: { session_file: '', pid: '' }, - call: function(req, args) { - if (!args.session_file || !args.pid) - return { error: 'Invalid arguments' }; - - try { - unlink(args.session_file); - system(`kill -15 ${args.pid}`); - return { success: true }; - } catch (e) { - return { error: e }; - } - } - } - } -}); - -conn.listen(); diff --git a/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-user.uc b/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-user.uc deleted file mode 100644 index 81530485..00000000 --- a/luci-app-pppoe-user/root/usr/share/rpcd/ucode/pppoe-user.uc +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/ucode -/* /usr/share/ucode/pppoe-user.uc */ - -import { readfile, listdir, stat } from 'fs'; -import { exec } from 'ubus'; -import { parse } from 'jsonc'; - -const SESSION_PATH = '/var/etc/pppoe-user/session'; -const LOG_PATH = '/var/pppoe-user/log/interface.log'; - -// 获取在线用户列表 -export function get_online_users() { - let users = []; - let count = 0; - - // 统计 ppp 接口数量 (模拟原 lua 逻辑) - try { - let dev = readfile('/proc/net/dev'); - if (dev) { - for (let line in split(dev, /\n/)) { - if (match(line, /^\s*ppp/)) count++; - } - } - } catch (e) {} - - if (!stat(SESSION_PATH)) return { count: count, sessions: [] }; - - let files = listdir(SESSION_PATH); - if (!files) return { count: count, sessions: [] }; - - for (let filename in files) { - let filepath = `${SESSION_PATH}/${filename}`; - if (!stat(filepath)?.is_regular) continue; - - try { - let content = readfile(filepath); - if (content) { - let data = parse(content); - if (data) { - data.session_file = filepath; - push(users, data); - } - } - } catch (e) { - warn(`Failed to read ${filepath}: ${e}`); - } - } - - return { count: count, sessions: users }; -} - -// 强制下线用户 -export function kill_user(session_file, pid) { - if (!session_file || !pid) return { error: 'Invalid parameters' }; - - try { - // 删除会话文件 - unlink(session_file); - - // 杀死进程 - let ret = system(`kill -15 ${pid}`); - - return { success: true }; - } catch (e) { - return { error: e }; - } -} - -// 获取接口日志 -export function get_interface_log() { - if (!stat(LOG_PATH)) return ''; - - try { - // 读取最后 200 行 (简单实现,ucode 没有直接的 tail,需读取后分割) - let content = readfile(LOG_PATH); - if (!content) return ''; - - let lines = split(content, /\n/); - let tail_lines = slice(lines, -200); - // 反转以符合原逻辑 (最新在上) - return join(reverse(tail_lines), '\n'); - } catch (e) { - return `Error reading log: ${e}`; - } -} - -// 获取下线用户统计 (简单模拟,实际需解析 UCI) -export function get_downtime_count() { - // 这里可以通过 ubus 调用 uci 或者直接解析 /etc/config/pppoe-user - // 为简化,建议在 JS 层直接处理 UCI 数据,或者在此处调用 uci get - try { - let res = exec('uci', { 'command': 'show', 'params': ['pppoe-user'] }); - if (res && res.output) { - let lines = split(res.output, /\n/); - let cnt = 0; - for (let line in lines) { - if (match(line, /=enabled$/)) { // 粗略匹配,更严谨需解析 value - // 实际上 ucidef 或 uci get 更好,这里仅作演示逻辑占位 - // 建议在前端 JS 直接遍历 uci.load('pppoe-user') - } - } - // 由于 ucode 直接调 uci 命令解析较繁琐,推荐此逻辑移至前端 JS 处理 UCI 对象 - return 0; - } - } catch (e) {} - return 0; -} diff --git a/luci-app-pppoe-user/root/usr/share/ucitrack/luci-app-pppoe-user.json b/luci-app-pppoe-user/root/usr/share/ucitrack/luci-app-pppoe-user.json deleted file mode 100644 index 3ed4d5ef..00000000 --- a/luci-app-pppoe-user/root/usr/share/ucitrack/luci-app-pppoe-user.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "config": "pppoe-user", - "init": "pppoe-user" -} diff --git a/luci-app-pppoe-user/screenshots/001.jpg b/luci-app-pppoe-user/screenshots/001.jpg deleted file mode 100644 index 9f336272d9e3a3971f438fb1f4da8bf065a3992f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51381 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 diff --git a/luci-app-pppoe-user/screenshots/002.jpg b/luci-app-pppoe-user/screenshots/002.jpg deleted file mode 100644 index c1a01b16b1f44baa6357764e5597fcc53540386e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66636 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 diff --git a/luci-app-pppoe-user/screenshots/003.jpg b/luci-app-pppoe-user/screenshots/003.jpg deleted file mode 100644 index 9976fe4531a273855cbd06017e4d00d9f6bb2854..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62477 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