diff --git a/alist/Makefile b/alist/Makefile index 5421794e5..1da2c15fb 100644 --- a/alist/Makefile +++ b/alist/Makefile @@ -7,13 +7,13 @@ include $(TOPDIR)/rules.mk PKG_NAME:=alist -PKG_VERSION:=3.51.0 -PKG_WEB_VERSION:=3.51.0 +PKG_VERSION:=3.52.0 +PKG_WEB_VERSION:=3.52.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/alist-org/alist/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=5289bc33b301f34abfb22cb2b3070c10f100466fe7e8647e1b47dce5073c70f0 +PKG_HASH:=a56cb3c949f6a2d5a22a1c1ff51cb9fa94c9955c8a8812992482882fc909436d PKG_LICENSE:=GPL-3.0 PKG_LICENSE_FILE:=LICENSE @@ -23,7 +23,7 @@ define Download/$(PKG_NAME)-web FILE:=$(PKG_NAME)-web-$(PKG_WEB_VERSION).tar.gz URL_FILE:=dist.tar.gz URL:=https://github.com/alist-org/alist-web/releases/download/$(PKG_WEB_VERSION)/ - HASH:=4d898e427d3bd0093f5739318f445dce260db82d7162cf3f0884718c050a4032 + HASH:=a5e415b72b7ad89c0db7a3c47a96b460d7343ddd72f2801a09c9a1dbcb234412 endef PKG_BUILD_DEPENDS:=golang/host diff --git a/luci-app-openclash/Makefile b/luci-app-openclash/Makefile index 11649659f..b9b549e4f 100644 --- a/luci-app-openclash/Makefile +++ b/luci-app-openclash/Makefile @@ -1,7 +1,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-openclash -PKG_VERSION:=0.46.137 +PKG_VERSION:=0.47.001 PKG_MAINTAINER:=vernesong PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) @@ -60,9 +60,10 @@ define Build/Prepare chmod -R 0755 $(PKG_BUILD_DIR)/root/usr/share/openclash/ mkdir -p $(PKG_BUILD_DIR)/root/etc/openclash/config mkdir -p $(PKG_BUILD_DIR)/root/etc/openclash/rule_provider + mkdir -p $(PKG_BUILD_DIR)/root/etc/openclash/proxy_provider mkdir -p $(PKG_BUILD_DIR)/root/etc/openclash/backup mkdir -p $(PKG_BUILD_DIR)/root/etc/openclash/core - mkdir -p $(PKG_BUILD_DIR)/root/usr/share/openclash/backup + mkdir -p $(PKG_BUILD_DIR)/root/usr/share/openclash/backup/overwrite cp -f "$(PKG_BUILD_DIR)/root/etc/config/openclash" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash" >/dev/null 2>&1 cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/custom/openclash_custom_rules.list" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash_custom_rules.list" >/dev/null 2>&1 cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/custom/openclash_custom_rules_2.list" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash_custom_rules_2.list" >/dev/null 2>&1 @@ -78,6 +79,7 @@ define Build/Prepare cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/custom/openclash_custom_chnroute6_pass.list" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash_custom_chnroute6_pass.list" >/dev/null 2>&1 cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/custom/openclash_custom_firewall_rules.sh" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash_custom_firewall_rules.sh" >/dev/null 2>&1 cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/custom/openclash_custom_overwrite.sh" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/openclash_custom_overwrite.sh" >/dev/null 2>&1 + cp -f "$(PKG_BUILD_DIR)/root/etc/openclash/overwrite/default" "$(PKG_BUILD_DIR)/root/usr/share/openclash/backup/overwrite/default" >/dev/null 2>&1 exit 0 endef @@ -92,7 +94,7 @@ endef define Package/$(PKG_NAME)/preinst #!/bin/sh - if [ -f "/etc/config/openclash" ]; then + if [ -f "/etc/config/openclash" ] && [ ! -f "/tmp/openclash.bak" ]; then cp -f "/etc/config/openclash" "/tmp/openclash.bak" >/dev/null 2>&1 cp -rf "/etc/openclash" "/tmp/openclash" >/dev/null 2>&1 cp -rf "/usr/share/openclash/ui/yacd" "/tmp/openclash_yacd" >/dev/null 2>&1 @@ -112,11 +114,13 @@ define Package/$(PKG_NAME)/prerm uci -q set openclash.config.enable=0 uci -q commit openclash [ -n "$(pidof clash)" ] && /etc/init.d/openclash stop 2>/dev/null - cp -f "/etc/config/openclash" "/tmp/openclash.bak" >/dev/null 2>&1 - cp -rf "/etc/openclash" "/tmp/openclash" >/dev/null 2>&1 - cp -rf "/usr/share/openclash/ui/yacd" "/tmp/openclash_yacd" >/dev/null 2>&1 - cp -rf "/usr/share/openclash/ui/dashboard" "/tmp/openclash_dashboard" >/dev/null 2>&1 - cp -rf "/www/luci-static/resources/openclash/pac" "/tmp/pac" >/dev/null 2>&1 + if [ -f "/etc/config/openclash" ] && [ ! -f "/tmp/openclash.bak" ]; then + cp -f "/etc/config/openclash" "/tmp/openclash.bak" >/dev/null 2>&1 + cp -rf "/etc/openclash" "/tmp/openclash" >/dev/null 2>&1 + cp -rf "/usr/share/openclash/ui/yacd" "/tmp/openclash_yacd" >/dev/null 2>&1 + cp -rf "/usr/share/openclash/ui/dashboard" "/tmp/openclash_dashboard" >/dev/null 2>&1 + cp -rf "/www/luci-static/resources/openclash/pac" "/tmp/pac" >/dev/null 2>&1 + fi exit 0 endef @@ -140,7 +144,7 @@ define Package/$(PKG_NAME)/postrm rm -rf /tmp/rules_name >/dev/null 2>&1 rm -rf /tmp/rule_providers_name >/dev/null 2>&1 rm -rf /tmp/clash_last_version >/dev/null 2>&1 - rm -rf /usr/share/openclash/backup >/dev/null 2>&1 + rm -rf /usr/share/openclash >/dev/null 2>&1 rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_custom_domain.conf >/dev/null 2>&1 rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute_pass.conf >/dev/null 2>&1 rm -rf ${DNSMASQ_CONF_DIR}/dnsmasq_openclash_chnroute6_pass.conf >/dev/null 2>&1 @@ -148,8 +152,7 @@ define Package/$(PKG_NAME)/postrm rm -rf /tmp/etc/openclash >/dev/null 2>&1 rm -rf /tmp/openclash_edit_file_name >/dev/null 2>&1 rm -rf /tmp/openclash_announcement >/dev/null 2>&1 - rm -rf /usr/share/openclash/ui/xd >/dev/null 2>&1 - rm -rf /www/luci-static/resources/openclash/pac >/dev/null 2>&1 + rm -rf /www/luci-static/resources/openclash >/dev/null 2>&1 sed -i '/OpenClash Append/,/OpenClash Append End/d' "/usr/lib/lua/luci/model/network.lua" >/dev/null 2>&1 sed -i '/.*kB maximum content size*/c\HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size' /usr/lib/lua/luci/http.lua >/dev/null 2>&1 sed -i '/.*kB maximum content size*/c\export let HTTP_MAX_CONTENT = 1024*100; // 100 kB maximum content size' /usr/share/ucode/luci/http.uc >/dev/null 2>&1 diff --git a/luci-app-openclash/luasrc/controller/openclash.lua b/luci-app-openclash/luasrc/controller/openclash.lua index ef1cd34e2..79e09b5ed 100644 --- a/luci-app-openclash/luasrc/controller/openclash.lua +++ b/luci-app-openclash/luasrc/controller/openclash.lua @@ -26,7 +26,8 @@ function index() entry({"admin", "services", "openclash", "update_ma"},call("action_update_ma")) entry({"admin", "services", "openclash", "opupdate"},call("action_opupdate")) entry({"admin", "services", "openclash", "coreupdate"},call("action_coreupdate")) - entry({"admin", "services", "openclash", "flush_fakeip_cache"}, call("action_flush_fakeip_cache")) + entry({"admin", "services", "openclash", "flush_dns_cache"}, call("action_flush_dns_cache")) + entry({"admin", "services", "openclash", "flush_smart_cache"}, call("action_flush_smart_cache")) entry({"admin", "services", "openclash", "update_config"}, call("action_update_config")) entry({"admin", "services", "openclash", "download_rule"}, call("action_download_rule")) entry({"admin", "services", "openclash", "restore"}, call("action_restore_config")) @@ -102,6 +103,10 @@ function index() entry({"admin", "services", "openclash", "config_file_save"}, call("action_config_file_save")) entry({"admin", "services", "openclash", "upload_config"}, call("action_upload_config")) entry({"admin", "services", "openclash", "add_subscription"}, call("action_add_subscription")) + entry({"admin", "services", "openclash", "upload_overwrite"}, call("action_upload_overwrite")) + entry({"admin", "services", "openclash", "overwrite_subscribe_info"}, call("action_overwrite_subscribe_info")) + entry({"admin", "services", "openclash", "overwrite_file_list"}, call("action_overwrite_file_list")) + entry({"admin", "services", "openclash", "delete_overwrite_file"}, call("delete_overwrite_file")) end local fs = require "luci.openclash" @@ -118,7 +123,7 @@ else opkg = nil end -local core_path_mode = uci:get("openclash", "config", "small_flash_memory") +local core_path_mode = fs.uci_get("config", "small_flash_memory") if core_path_mode ~= "1" then meta_core_path="/etc/openclash/core/clash_meta" else @@ -135,12 +140,12 @@ end local function cn_port() if is_running() then - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then local config_filename = fs.basename(config_path) local runtime_config_path = "/etc/openclash/" .. config_filename local ruby_result = luci.sys.exec(string.format([[ - ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " + timeout 5 ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin config = YAML.load_file('%s') if config @@ -154,18 +159,18 @@ local function cn_port() end end end - " 2>/dev/null - ]], runtime_config_path)):gsub("%s+", "") - if ruby_result and ruby_result ~= "" then + " 2>/dev/null || echo "__RUBY_ERROR__" + ]], runtime_config_path)):gsub("\n", "") + if ruby_result and ruby_result ~= "" and ruby_result ~= "__RUBY_ERROR__" then return ruby_result end end end - return uci:get("openclash", "config", "cn_port") or "9090" + return fs.uci_get("config", "cn_port") or "9090" end local function mode() - return uci:get("openclash", "config", "en_mode") + return fs.uci_get("config", "en_mode") end local function daip() @@ -174,12 +179,12 @@ end local function dase() if is_running() then - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then local config_filename = fs.basename(config_path) local runtime_config_path = "/etc/openclash/" .. config_filename local ruby_result = luci.sys.exec(string.format([[ - ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " + timeout 5 ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin config = YAML.load_file('%s') if config @@ -187,24 +192,26 @@ local function dase() puts \"#{dase}\" end end - " 2>/dev/null - ]], runtime_config_path)):gsub("%s+", "") - return ruby_result + " 2>/dev/null || echo "__RUBY_ERROR__" + ]], runtime_config_path)):gsub("\n", "") + if ruby_result and ruby_result ~= "" and ruby_result ~= "__RUBY_ERROR__" then + return ruby_result + end end end - return uci:get("openclash", "config", "dashboard_password") + return fs.uci_get("config", "dashboard_password") end local function db_foward_domain() - return uci:get("openclash", "config", "dashboard_forward_domain") + return fs.uci_get("config", "dashboard_forward_domain") end local function db_foward_port() - return uci:get("openclash", "config", "dashboard_forward_port") + return fs.uci_get("config", "dashboard_forward_port") end local function db_foward_ssl() - return uci:get("openclash", "config", "dashboard_forward_ssl") or 0 + return fs.uci_get("config", "dashboard_forward_ssl") or 0 end local function check_lastversion() @@ -215,7 +222,7 @@ end local function startlog() local info = "" local line_trans = "" - if nixio.fs.access("/tmp/openclash_start.log") then + if fs.access("/tmp/openclash_start.log") then info = luci.sys.exec("sed -n '$p' /tmp/openclash_start.log 2>/dev/null") line_trans = info if string.len(info) > 0 then @@ -250,7 +257,7 @@ local function coremodel() end local function check_core() - if not nixio.fs.access(meta_core_path) then + if not fs.access(meta_core_path) then return "0" else return "1" @@ -259,7 +266,7 @@ end local function coremetacv() local v = "0" - if not nixio.fs.access(meta_core_path) then + if not fs.access(meta_core_path) then return v else v = luci.sys.exec(string.format("%s -v 2>/dev/null |awk -F ' ' '{print $3}' |head -1 |tr -d '\n'", meta_core_path)) @@ -273,7 +280,7 @@ end local function corelv() local status = process_status("/usr/share/openclash/clash_version.sh") local core_meta_lv = "" - local core_smart_enable = uci:get("openclash", "config", "smart_enable") or "0" + local core_smart_enable = fs.uci_get("config", "smart_enable") or "0" if not status then if fs.access("/tmp/clash_last_version") and tonumber(os.time() - fs.mtime("/tmp/clash_last_version")) < 1800 then if core_smart_enable == "1" then @@ -340,15 +347,15 @@ local function coreup() end local function corever() - return uci:get("openclash", "config", "core_version") or "0" + return fs.uci_get("config", "core_version") or "0" end local function release_branch() - return uci:get("openclash", "config", "release_branch") or "master" + return fs.uci_get("config", "release_branch") or "master" end local function smart_enable() - return uci:get("openclash", "config", "smart_enable") or "0" + return fs.uci_get("config", "smart_enable") or "0" end local function save_corever_branch() @@ -398,18 +405,34 @@ function download_rule() return state end -function action_flush_fakeip_cache() +function action_flush_dns_cache() local state = 0 if is_running() then local daip = daip() local dase = dase() or "" local cn_port = cn_port() if not daip or not cn_port then return end - state = luci.sys.exec(string.format('curl -sL -m 3 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XPOST http://"%s":"%s"/cache/fakeip/flush', dase, daip, cn_port)) - end + fake_ip_state = luci.sys.exec(string.format('curl -sL -m 3 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XPOST http://"%s":"%s"/cache/fakeip/flush', dase, daip, cn_port)) + dns_state = luci.sys.exec(string.format('curl -sL -m 3 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XPOST http://"%s":"%s"/cache/dns/flush', dase, daip, cn_port)) + end luci.http.prepare_content("application/json") luci.http.write_json({ - flush_status = state; + flush_status = dns_state; + }) +end + +function action_flush_smart_cache() + local state = 0 + if is_running() then + local daip = daip() + local dase = dase() or "" + local cn_port = cn_port() + if not daip or not cn_port then return end + flush_state = luci.sys.exec(string.format('curl -sL -m 3 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XPOST http://"%s":"%s"/cache/smart/flush', dase, daip, cn_port)) + end + luci.http.prepare_content("application/json") + luci.http.write_json({ + flush_status = flush_state; }) end @@ -451,14 +474,16 @@ end function action_restore_config() uci:set("openclash", "config", "enable", "0") uci:commit("openclash") + luci.sys.call("mkdir -p /etc/openclash/custom >/dev/null 2>&1") + luci.sys.call("mkdir -p /etc/openclash/overwrite >/dev/null 2>&1") luci.sys.call("/etc/init.d/openclash stop >/dev/null 2>&1") - luci.sys.call("cp '/usr/share/openclash/backup/openclash' '/etc/config/openclash' >/dev/null 2>&1 &") + luci.sys.call("cp /usr/share/openclash/backup/openclash /etc/config/openclash >/dev/null 2>&1 &") luci.sys.call("cp /usr/share/openclash/backup/openclash_custom* /etc/openclash/custom/ >/dev/null 2>&1 &") luci.sys.call("cp /usr/share/openclash/backup/openclash_force_sniffing* /etc/openclash/custom/ >/dev/null 2>&1 &") luci.sys.call("cp /usr/share/openclash/backup/openclash_sniffing* /etc/openclash/custom/ >/dev/null 2>&1 &") - luci.sys.call("cp /usr/share/openclash/backup/yml_change.sh /usr/share/openclash/yml_change.sh >/dev/null 2>&1 &") luci.sys.call("cp /usr/share/openclash/backup/china_ip_route.ipset /etc/openclash/china_ip_route.ipset >/dev/null 2>&1 &") luci.sys.call("cp /usr/share/openclash/backup/china_ip6_route.ipset /etc/openclash/china_ip6_route.ipset >/dev/null 2>&1 &") + luci.sys.call("cp /usr/share/openclash/backup/overwrite/default /etc/openclash/overwrite/default >/dev/null 2>&1 &") luci.sys.call("rm -rf /etc/openclash/history/* >/dev/null 2>&1 &") end @@ -494,8 +519,8 @@ end local function dler_login() local info, token, get_sub, sub_info, sub_key, sub_match local sub_path = "/tmp/dler_sub" - local email = uci:get("openclash", "config", "dler_email") - local passwd = uci:get("openclash", "config", "dler_passwd") + local email = fs.uci_get("config", "dler_email") + local passwd = fs.uci_get("config", "dler_passwd") if email and passwd then info = luci.sys.exec(string.format("curl -sL -H 'Content-Type: application/json' -d '{\"email\":\"%s\", \"passwd\":\"%s\"}' -X POST https://dler.cloud/api/v1/login", email, passwd)) if info then @@ -555,7 +580,7 @@ end local function dler_logout() local info, token - local token = uci:get("openclash", "config", "dler_token") + local token = fs.uci_get("config", "dler_token") if token then info = luci.sys.exec(string.format("curl -sL -H 'Content-Type: application/json' -d '{\"access_token\":\"%s\"}' -X POST https://dler.cloud/api/v1/logout", token)) if info then @@ -585,13 +610,13 @@ end local function dler_info() local info, path, get_info - local token = uci:get("openclash", "config", "dler_token") - local email = uci:get("openclash", "config", "dler_email") - local passwd = uci:get("openclash", "config", "dler_passwd") + local token = fs.uci_get("config", "dler_token") + local email = fs.uci_get("config", "dler_email") + local passwd = fs.uci_get("config", "dler_passwd") path = "/tmp/dler_info" if token and email and passwd then get_info = string.format("curl -sL -H 'Content-Type: application/json' -d '{\"email\":\"%s\", \"passwd\":\"%s\"}' -X POST https://dler.cloud/api/v1/information -o %s", email, passwd, path) - if not nixio.fs.access(path) then + if not fs.access(path) then luci.sys.exec(get_info) else if fs.readfile(path) == "" or not fs.readfile(path) then @@ -627,10 +652,10 @@ end local function dler_checkin() local info local path = "/tmp/dler_checkin" - local token = uci:get("openclash", "config", "dler_token") - local email = uci:get("openclash", "config", "dler_email") - local passwd = uci:get("openclash", "config", "dler_passwd") - local multiple = uci:get("openclash", "config", "dler_checkin_multiple") or 1 + local token = fs.uci_get("config", "dler_token") + local email = fs.uci_get("config", "dler_email") + local passwd = fs.uci_get("config", "dler_passwd") + local multiple = fs.uci_get("config", "dler_checkin_multiple") or 1 if token and email and passwd then info = luci.sys.exec(string.format("curl -sL -H 'Content-Type: application/json' -d '{\"email\":\"%s\", \"passwd\":\"%s\", \"multiple\":\"%s\"}' -X POST https://dler.cloud/api/v1/checkin", email, passwd, multiple)) if info then @@ -667,8 +692,8 @@ local function config_name() end local function config_path() - if uci:get("openclash", "config", "config_path") then - return string.sub(uci:get("openclash", "config", "config_path"), 23, -1) + if fs.uci_get("config", "config_path") then + return string.sub(fs.uci_get("config", "config_path"), 23, -1) else return "" end @@ -691,7 +716,7 @@ function action_switch_config() return end - if not nixio.fs.access(config_file) then + if not fs.access(config_file) then luci.http.prepare_content("application/json") luci.http.write_json({ status = "error", @@ -886,26 +911,24 @@ function sub_info_get() end function action_rule_mode() - local mode, info, core_type + local mode, info if is_running() then local daip = daip() local dase = dase() or "" local cn_port = cn_port() - core_type = uci:get("openclash", "config", "core_type") or "Meta" if not daip or not cn_port then return end info = json.parse(luci.sys.exec(string.format('curl -sL -m 3 -H "Content-Type: application/json" -H "Authorization: Bearer %s" -XGET http://"%s":"%s"/configs', dase, daip, cn_port))) if info then mode = info["mode"] else - mode = uci:get("openclash", "config", "proxy_mode") or "rule" + mode = fs.uci_get("config", "proxy_mode") or "rule" end else - mode = uci:get("openclash", "config", "proxy_mode") or "rule" + mode = fs.uci_get("config", "proxy_mode") or "rule" end luci.http.prepare_content("application/json") luci.http.write_json({ - mode = mode, - core_type = core_type; + mode = mode; }) end @@ -950,7 +973,7 @@ end function action_switch_run_mode() local mode, operation_mode mode = luci.http.formvalue("run_mode") - operation_mode = uci:get("openclash", "config", "operation_mode") + operation_mode = fs.uci_get("config", "operation_mode") if operation_mode == "redir-host" then uci:set("openclash", "config", "en_mode", "redir-host"..mode) elseif operation_mode == "fake-ip" then @@ -973,10 +996,10 @@ function action_log_level() if info then level = info["log-level"] else - level = uci:get("openclash", "config", "log_level") or "info" + level = fs.uci_get("config", "log_level") or "info" end else - level = uci:get("openclash", "config", "log_level") or "info" + level = fs.uci_get("config", "log_level") or "info" end luci.http.prepare_content("application/json") luci.http.write_json({ @@ -1042,7 +1065,7 @@ function action_toolbar_show_sys() cpu = "0" end - load_avg = luci.sys.exec("awk '{print $2; exit}' /proc/loadavg 2>/dev/null"):gsub("%s+", "") or "0" + load_avg = luci.sys.exec("awk '{print $2; exit}' /proc/loadavg 2>/dev/null"):gsub("\n", "") or "0" if not string.match(load_avg, "^[0-9]*%.?[0-9]*$") then load_avg = "0" @@ -1102,7 +1125,7 @@ function action_toolbar_show() cpu = "0" end - load_avg = luci.sys.exec("awk '{print $2; exit}' /proc/loadavg 2>/dev/null"):gsub("%s+", "") or "0" + load_avg = luci.sys.exec("awk '{print $2; exit}' /proc/loadavg 2>/dev/null"):gsub("\n", "") or "0" if not string.match(load_avg, "^[0-9]*%.?[0-9]*$") then load_avg = "0" @@ -1182,8 +1205,8 @@ function action_one_key_update_check() end function action_dashboard_type() - local dashboard_type = uci:get("openclash", "config", "dashboard_type") or "Official" - local yacd_type = uci:get("openclash", "config", "yacd_type") or "Official" + local dashboard_type = fs.uci_get("config", "dashboard_type") or "Official" + local yacd_type = fs.uci_get("config", "yacd_type") or "Official" luci.http.prepare_content("application/json") luci.http.write_json({ dashboard_type = dashboard_type, @@ -1219,7 +1242,7 @@ function action_switch_dashboard() end function action_op_mode() - local op_mode = uci:get("openclash", "config", "operation_mode") + local op_mode = fs.uci_get("config", "operation_mode") luci.http.prepare_content("application/json") luci.http.write_json({ op_mode = op_mode; @@ -1227,7 +1250,7 @@ function action_op_mode() end function action_switch_mode() - local switch_mode = uci:get("openclash", "config", "operation_mode") + local switch_mode = fs.uci_get("config", "operation_mode") if switch_mode == "redir-host" then uci:set("openclash", "config", "operation_mode", "fake-ip") uci:commit("openclash") @@ -1251,21 +1274,21 @@ function action_status() db_foward_domain = db_foward_domain(), db_forward_ssl = db_foward_ssl(), cn_port = cn_port(), - core_type = uci:get("openclash", "config", "core_type") or "Meta"; + core_type = fs.uci_get("config", "core_type") or "Meta"; }) end function action_lastversion() luci.http.prepare_content("application/json") luci.http.write_json({ - lastversion = check_lastversion(); + lastversion = check_lastversion(); }) end function action_start() luci.http.prepare_content("application/json") luci.http.write_json({ - startlog = startlog(); + startlog = startlog(); }) end @@ -1293,19 +1316,19 @@ end function action_update_info() luci.http.prepare_content("application/json") luci.http.write_json({ - corever = corever(), - release_branch = release_branch(), - smart_enable = smart_enable(); + corever = corever(), + release_branch = release_branch(), + smart_enable = smart_enable(); }) end function action_update_ma() luci.http.prepare_content("application/json") luci.http.write_json({ - oplv = oplv(), - pkg_type = pkg_type(), - corelv = corelv(), - corever = corever(); + oplv = oplv(), + pkg_type = pkg_type(), + corelv = corelv(), + corever = corever(); }) end @@ -1655,7 +1678,7 @@ function rename_file() local new_backup_file_path = "/etc/openclash/backup/" .. new_file_name if fs.rename(old_file_path, new_file_path) then if file_path == "/etc/openclash/config/" then - if uci:get("openclash", "config", "config_path") == old_file_path then + if fs.uci_get("config", "config_path") == old_file_path then uci:set("openclash", "config", "config_path", new_file_path) end @@ -2180,10 +2203,23 @@ function action_website_check() luci.http.write_json(result) return end - + + local test_domain = domain + local test_url + + if test_domain:match("^https?://") then + test_domain = test_domain:gsub("^https?://([^/]+)/?.*$", "%1") + end + + if domain == "https://raw.githubusercontent.com/" or test_domain == "raw.githubusercontent.com" then + test_url = "https://raw.githubusercontent.com/vernesong/OpenClash/dev/img/logo.png" + else + test_url = "https://" .. test_domain .. "/favicon.ico" + end + local cmd = string.format( - 'curl -sL -m 5 --connect-timeout 3 -w "%%{http_code},%%{time_total},%%{time_connect},%%{time_appconnect}" "https://%s/favicon.ico" -o /dev/null 2>/dev/null', - domain + 'curl -sL -m 5 --connect-timeout 3 -w "%%{http_code},%%{time_total},%%{time_connect},%%{time_appconnect}" "%s" -o /dev/null 2>/dev/null', + test_url ) local output = luci.sys.exec(cmd) @@ -2209,9 +2245,15 @@ function action_website_check() result.success = true result.response_time = response_time else + local fallback_url + if domain == "https://raw.githubusercontent.com/" or test_domain == "raw.githubusercontent.com" then + fallback_url = "https://raw.githubusercontent.com/vernesong/OpenClash/dev/img/logo.png" + else + fallback_url = "https://" .. test_domain .. "/" + end local fallback_cmd = string.format( - 'curl -sI -m 3 --connect-timeout 2 -w "%%{http_code},%%{time_total},%%{time_appconnect}" "https://%s/" -o /dev/null 2>/dev/null', - domain + 'curl -sI -m 5 --connect-timeout 3 -w "%%{http_code},%%{time_total},%%{time_appconnect}" "%s" -o /dev/null 2>/dev/null', + fallback_url ) local fallback_output = luci.sys.exec(fallback_cmd) @@ -2267,7 +2309,7 @@ function action_proxy_info() } local function get_info_from_uci() - local mixed_port = uci:get("openclash", "config", "mixed_port") + local mixed_port = fs.uci_get("config", "mixed_port") if mixed_port and mixed_port ~= "" then result.mixed_port = mixed_port else @@ -2287,14 +2329,14 @@ function action_proxy_info() end) end - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then local config_filename = fs.basename(config_path) local runtime_config_path = "/etc/openclash/" .. config_filename - if nixio.fs.access(runtime_config_path) then + if fs.access(runtime_config_path) then local ruby_result = luci.sys.exec(string.format([[ - ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " + timeout 5 ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin config = YAML.load_file('%s') mixed_port = '' @@ -2320,44 +2362,47 @@ function action_proxy_info() rescue puts ',,' end - " 2>/dev/null - ]], runtime_config_path)):gsub("%s+", "") + " 2>/dev/null || echo "__RUBY_ERROR__" + ]], runtime_config_path)):gsub("\n", "") - local runtime_mixed_port, runtime_auth_user, runtime_auth_pass = ruby_result:match("([^,]*),([^,]*),([^,]*)") - - if runtime_mixed_port and runtime_mixed_port ~= "" then - result.mixed_port = runtime_mixed_port - else - local uci_mixed_port = uci:get("openclash", "config", "mixed_port") - if uci_mixed_port and uci_mixed_port ~= "" then - result.mixed_port = uci_mixed_port + if ruby_result and ruby_result ~= "" and ruby_result ~= "__RUBY_ERROR__" then + local runtime_mixed_port, runtime_auth_user, runtime_auth_pass = ruby_result:match("([^,]*),([^,]*),([^,]*)") + + if runtime_mixed_port and runtime_mixed_port ~= "" then + result.mixed_port = runtime_mixed_port else - result.mixed_port = "7893" - end - end - - if runtime_auth_user and runtime_auth_user ~= "" and runtime_auth_pass and runtime_auth_pass ~= "" then - result.auth_user = runtime_auth_user - result.auth_pass = runtime_auth_pass - else - uci:foreach("openclash", "authentication", function(section) - if section.enabled == "1" and result.auth_user == "" then - if section.username and section.username ~= "" then - result.auth_user = section.username - end - if section.password and section.password ~= "" then - result.auth_pass = section.password - end - return false + local uci_mixed_port = fs.uci_get("config", "mixed_port") + if uci_mixed_port and uci_mixed_port ~= "" then + result.mixed_port = uci_mixed_port + else + result.mixed_port = "7893" end - end) + end + + if runtime_auth_user and runtime_auth_user ~= "" and runtime_auth_pass and runtime_auth_pass ~= "" then + result.auth_user = runtime_auth_user + result.auth_pass = runtime_auth_pass + else + uci:foreach("openclash", "authentication", function(section) + if section.enabled == "1" and result.auth_user == "" then + if section.username and section.username ~= "" then + result.auth_user = section.username + end + if section.password and section.password ~= "" then + result.auth_pass = section.password + end + return false + end + end) + end + luci.http.prepare_content("application/json") + luci.http.write_json(result) + return end - else - get_info_from_uci() end - else - get_info_from_uci() end + + get_info_from_uci() luci.http.prepare_content("application/json") luci.http.write_json(result) @@ -2372,26 +2417,26 @@ function action_oc_settings() } local function get_uci_settings() - local meta_sniffer = uci:get("openclash", "config", "enable_meta_sniffer") + local meta_sniffer = fs.uci_get("config", "enable_meta_sniffer") if meta_sniffer == "1" then result.meta_sniffer = "1" end - local respect_rules = uci:get("openclash", "config", "enable_respect_rules") + local respect_rules = fs.uci_get("config", "enable_respect_rules") if respect_rules == "1" then result.respect_rules = "1" end end if is_running() then - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then local config_filename = fs.basename(config_path) local runtime_config_path = "/etc/openclash/" .. config_filename - if nixio.fs.access(runtime_config_path) then + if fs.access(runtime_config_path) then local ruby_result = luci.sys.exec(string.format([[ - ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " + timeout 5 ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin config = YAML.load_file('%s') if config @@ -2404,13 +2449,17 @@ function action_oc_settings() rescue puts '0,0' end - " 2>/dev/null - ]], runtime_config_path)):gsub("%s+", "") + " 2>/dev/null || echo "__RUBY_ERROR__" + ]], runtime_config_path)):gsub("\n", "") - local sniffer_result, respect_rules_result = ruby_result:match("(%d),(%d)") - if sniffer_result and respect_rules_result then - result.meta_sniffer = sniffer_result - result.respect_rules = respect_rules_result + if ruby_result and ruby_result ~= "" and ruby_result ~= "__RUBY_ERROR__" then + local sniffer_result, respect_rules_result = ruby_result:match("(%d),(%d)") + if sniffer_result and respect_rules_result then + result.meta_sniffer = sniffer_result + result.respect_rules = respect_rules_result + else + get_uci_settings() + end else get_uci_settings() end @@ -2424,7 +2473,7 @@ function action_oc_settings() get_uci_settings() end - local oversea = uci:get("openclash", "config", "china_ip_route") + local oversea = fs.uci_get("config", "china_ip_route") if oversea == "1" then result.oversea = "1" elseif oversea == "2" then @@ -2433,7 +2482,7 @@ function action_oc_settings() result.oversea = "0" end - local stream_unlock = uci:get("openclash", "config", "stream_auto_select") + local stream_unlock = fs.uci_get("config", "stream_auto_select") if stream_unlock == "1" then result.stream_unlock = "1" end @@ -2452,7 +2501,7 @@ function action_switch_oc_setting() end local function get_runtime_config_path() - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if not config_path then return nil end @@ -2492,10 +2541,6 @@ function action_switch_oc_setting() end if setting == "meta_sniffer" then - uci:set("openclash", "config", "enable_meta_sniffer", value) - uci:set("openclash", "config", "enable_meta_sniffer_pure_ip", value) - uci:commit("openclash") - if is_running() then local runtime_config_path = get_runtime_config_path() local ruby_cmd @@ -2591,12 +2636,13 @@ function action_switch_oc_setting() if not update_runtime_config(ruby_cmd) then return end + else + uci:set("openclash", "config", "enable_meta_sniffer", value) + uci:set("openclash", "config", "enable_meta_sniffer_pure_ip", value) + uci:commit("openclash") end elseif setting == "respect_rules" then - uci:set("openclash", "config", "enable_respect_rules", value) - uci:commit("openclash") - if is_running() then local runtime_config_path = get_runtime_config_path() local target_value = (value == "1") and "true" or "false" @@ -2643,39 +2689,43 @@ function action_switch_oc_setting() if not update_runtime_config(ruby_cmd) then return end + else + uci:set("openclash", "config", "enable_respect_rules", value) + uci:commit("openclash") end elseif setting == "oversea" then uci:set("openclash", "config", "china_ip_route", value) uci:commit("openclash") - if is_running() then + uci:set("openclash", "@overwrite[0]", "china_ip_route", value) + uci:commit("openclash") luci.sys.exec("/etc/init.d/openclash restart >/dev/null 2>&1 &") end elseif setting == "stream_unlock" then uci:set("openclash", "config", "stream_auto_select", value) - if not uci:get("openclash", "config", "stream_auto_select_interval") then + if not fs.uci_get("config", "stream_auto_select_interval") then uci:set("openclash", "config", "stream_auto_select_interval", "10") end - if not uci:get("openclash", "config", "stream_auto_select_logic") then + if not fs.uci_get("config", "stream_auto_select_logic") then uci:set("openclash", "config", "stream_auto_select_logic", "Urltest") end - if not uci:get("openclash", "config", "stream_auto_select_expand_group") then + if not fs.uci_get("config", "stream_auto_select_expand_group") then uci:set("openclash", "config", "stream_auto_select_expand_group", "0") end uci:set("openclash", "config", "stream_auto_select_netflix", "1") - if not uci:get("openclash", "config", "stream_auto_select_group_key_netflix") then + if not fs.uci_get("config", "stream_auto_select_group_key_netflix") then uci:set("openclash", "config", "stream_auto_select_group_key_netflix", "Netflix|奈飞") end uci:set("openclash", "config", "stream_auto_select_disney", "1") - if not uci:get("openclash", "config", "stream_auto_select_group_key_disney") then + if not fs.uci_get("config", "stream_auto_select_group_key_disney") then uci:set("openclash", "config", "stream_auto_select_group_key_disney", "Disney|迪士尼") end uci:set("openclash", "config", "stream_auto_select_hbo_max", "1") - if not uci:get("openclash", "config", "stream_auto_select_group_key_hbo_max") then + if not fs.uci_get("config", "stream_auto_select_group_key_hbo_max") then uci:set("openclash", "config", "stream_auto_select_group_key_hbo_max", "HBO|HBO Max") end uci:commit("openclash") @@ -2714,14 +2764,14 @@ function action_generate_pac() end) end - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then local config_filename = fs.basename(config_path) local runtime_config_path = "/etc/openclash/" .. config_filename - if nixio.fs.access(runtime_config_path) then + if fs.access(runtime_config_path) then local ruby_result = luci.sys.exec(string.format([[ - ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " + timeout 5 ruby -ryaml -rYAML -I "/usr/share/openclash" -E UTF-8 -e " begin config = YAML.load_file('%s') if config && config['authentication'] && config['authentication'].is_a?(Array) && !config['authentication'].empty? @@ -2738,26 +2788,26 @@ function action_generate_pac() rescue puts ',' end - " 2>/dev/null - ]], runtime_config_path)):gsub("%s+", "") - - local runtime_user, runtime_pass = ruby_result:match("([^,]*),([^,]*)") - if runtime_user and runtime_user ~= "" and runtime_pass and runtime_pass ~= "" then - auth_user = runtime_user - auth_pass = runtime_pass - auth_exists = true - else - get_auth_from_uci() + " 2>/dev/null || echo "__RUBY_ERROR__" + ]], runtime_config_path)):gsub("\n", "") + + if ruby_result and ruby_result ~= "" and ruby_result ~= "__RUBY_ERROR__" then + local runtime_user, runtime_pass = ruby_result:match("([^,]*),([^,]*)") + if runtime_user and runtime_user ~= "" and runtime_pass and runtime_pass ~= "" then + auth_user = runtime_user + auth_pass = runtime_pass + auth_exists = true + end end - else - get_auth_from_uci() end - else + end + + if not auth_exists then get_auth_from_uci() end local proxy_ip = daip() - local mixed_port = uci:get("openclash", "config", "mixed_port") or "7893" + local mixed_port = fs.uci_get("config", "mixed_port") or "7893" if not proxy_ip then result.error = "Unable to get proxy IP" @@ -2802,7 +2852,7 @@ function action_generate_pac() local existing_files = luci.sys.exec(find_cmd) if existing_files and existing_files ~= "" then for file_path in existing_files:gmatch("[^\n]+") do - if nixio.fs.access(file_path) then + if fs.access(file_path) then local file_content = fs.readfile(file_path) if file_content then local existing_proxy = string.match(file_content, 'return%s+"(PROXY%s+[^"]*)"') @@ -2977,7 +3027,7 @@ function generate_pac_content(proxy_ip, proxy_port, auth_user, auth_pass) local ipv4_networks = {} local ipv4_file = "/etc/openclash/custom/openclash_custom_localnetwork_ipv4.list" - if nixio.fs.access(ipv4_file) then + if fs.access(ipv4_file) then local content = fs.readfile(ipv4_file) if content then for line in content:gmatch("[^\r\n]+") do @@ -3016,7 +3066,7 @@ function generate_pac_content(proxy_ip, proxy_port, auth_user, auth_pass) local ipv6_networks = {} local ipv6_file = "/etc/openclash/custom/openclash_custom_localnetwork_ipv6.list" - if nixio.fs.access(ipv6_file) then + if fs.access(ipv6_file) then local content = fs.readfile(ipv6_file) if content then for line in content:gmatch("[^\r\n]+") do @@ -3137,6 +3187,10 @@ function FindProxyForURLEx(url, host) { return pac_script end +local function is_safe_filename(filename) + return filename and filename:match("^[%w%._%-]+$") and not filename:match("^%.") +end + function action_oc_action() local action = luci.http.formvalue("action") local config_file = luci.http.formvalue("config_file") @@ -3148,7 +3202,7 @@ function action_oc_action() if config_file and config_file ~= "" then local config_path = "/etc/openclash/config/" .. config_file - if not nixio.fs.access(config_path) then + if not fs.access(config_path) then luci.http.status(404, "Config file not found") return end @@ -3159,7 +3213,11 @@ function action_oc_action() if action == "start" then uci:set("openclash", "config", "enable", "1") uci:commit("openclash") - luci.sys.call("/etc/init.d/openclash start >/dev/null 2>&1") + if not is_running() then + luci.sys.call("/etc/init.d/openclash start >/dev/null 2>&1") + else + luci.sys.call("/etc/init.d/openclash restart >/dev/null 2>&1") + end elseif action == "stop" then uci:set("openclash", "config", "enable", "0") uci:commit("openclash") @@ -3182,25 +3240,27 @@ function action_config_file_list() local config_files = {} local current_config = "" - local config_path = uci:get("openclash", "config", "config_path") + local config_path = fs.uci_get("config", "config_path") if config_path then current_config = config_path end local config_dir = "/etc/openclash/config/" - if nixio.fs.access(config_dir) then - for file in nixio.fs.dir(config_dir) do - local full_path = config_dir .. file - local stat = nixio.fs.stat(full_path) - - if stat and stat.type == "reg" then - if string.match(file, "%.ya?ml$") then - table.insert(config_files, { - name = file, - path = full_path, - size = stat.size, - mtime = stat.mtime - }) + if fs.access(config_dir) then + local files = fs.dir(config_dir) + if files then + for _, file in ipairs(files) do + local full_path = config_dir .. file + local stat = fs.stat(full_path) + if stat and stat.type == "regular" then + if string.match(file, "%.ya?ml$") then + table.insert(config_files, { + name = file, + path = full_path, + size = stat.size, + mtime = stat.mtime + }) + end end end end @@ -3235,15 +3295,15 @@ function action_upload_config() if not filename or filename == "" then filename = "upload_" .. os.date("%Y%m%d_%H%M%S") end - - if string.find(filename, "[/\\]") or string.find(filename, "%.%.") then + + if not is_safe_filename(filename) then luci.http.write_json({ status = "error", - message = "Invalid filename characters" + message = "Invalid filename" }) return end - + if not string.match(filename, "%.ya?ml$") then filename = filename .. ".yaml" end @@ -3299,7 +3359,7 @@ function action_upload_config() local written_content = fs.readfile(target_path) if not written_content or string.len(written_content) ~= file_size then - nixio.fs.unlink(target_path) + fs.unlink(target_path) luci.http.write_json({ status = "error", message = "File write verification failed" @@ -3331,71 +3391,44 @@ function action_config_file_read() return end - local is_overwrite = (config_file == "/etc/openclash/custom/openclash_custom_overwrite.sh") - - if not is_overwrite then - if string.match(config_file, "^/etc/openclash/[^/%.]+%.ya?ml$") then - local stat = nixio.fs.stat(config_file) - if stat and stat.type == "reg" then - if stat.size > 10 * 1024 * 1024 then - luci.http.prepare_content("application/json") - luci.http.write_json({ - status = "error", - message = "Config file too large (max 10MB)" - }) - return - end - local content = fs.readfile(config_file) or "" - luci.http.prepare_content("application/json") - luci.http.write_json({ - status = "success", - content = content, - file_info = { - path = config_file, - size = stat.size, - mtime = stat.mtime, - readable_size = fs.filesize(stat.size), - last_modified = os.date("%Y-%m-%d %H:%M:%S", stat.mtime) - } - }) - return - else - luci.http.prepare_content("application/json") - luci.http.write_json({ - status = "success", - content = "", - file_info = { - path = config_file, - size = 0, - mtime = 0, - readable_size = "0 KB", - last_modified = "" - } - }) - return - end - end - if not string.match(config_file, "^/etc/openclash/config/[^/%.]+%.ya?ml$") then - luci.http.prepare_content("application/json") - luci.http.write_json({ - status = "error", - message = "Invalid config file path" - }) - return - end + local allow = false + if config_file == "/etc/openclash/custom/openclash_custom_overwrite.sh" then + allow = true + elseif config_file:match("^/etc/openclash/overwrite/[^/]+$") then + allow = true + elseif config_file:match("^/etc/openclash/[^/]+%.ya?ml$") then + allow = true + elseif config_file:match("^/etc/openclash/config/[^/]+%.ya?ml$") then + allow = true end - if not nixio.fs.access(config_file) then + if not allow then luci.http.prepare_content("application/json") luci.http.write_json({ status = "error", - message = "Config file does not exist: " .. config_file + message = "Invalid config file path" }) return end - local stat = nixio.fs.stat(config_file) - if not stat or stat.type ~= "reg" then + if not fs.access(config_file) then + luci.http.prepare_content("application/json") + luci.http.write_json({ + status = "success", + content = "", + file_info = { + path = config_file, + size = 0, + mtime = 0, + readable_size = "0 KB", + last_modified = "" + } + }) + return + end + + local stat = fs.stat(config_file) + if not stat or stat.type ~= "regular" then luci.http.prepare_content("application/json") luci.http.write_json({ status = "error", @@ -3454,7 +3487,7 @@ function action_config_file_save() return end - local is_overwrite = (config_file == "/etc/openclash/custom/openclash_custom_overwrite.sh") + local is_overwrite = (config_file == "/etc/openclash/custom/openclash_custom_overwrite.sh" or config_file:match("^/etc/openclash/overwrite/[^/]+$")) if not is_overwrite then if not string.match(config_file, "^/etc/openclash/config/[^/%.]+%.ya?ml$") then @@ -3465,6 +3498,15 @@ function action_config_file_save() }) return end + else + if not (config_file == "/etc/openclash/custom/openclash_custom_overwrite.sh" or config_file:match("^/etc/openclash/overwrite/[^/]+$")) then + luci.http.prepare_content("application/json") + luci.http.write_json({ + status = "error", + message = "Invalid overwrite file path" + }) + return + end end if string.len(content) > 10 * 1024 * 1024 then @@ -3477,7 +3519,7 @@ function action_config_file_save() end local backup_file = nil - if nixio.fs.access(config_file) then + if fs.access(config_file) then backup_file = config_file .. ".backup." .. os.time() local backup_success = luci.sys.call(string.format("cp '%s' '%s'", config_file, backup_file)) if backup_success ~= 0 then @@ -3534,7 +3576,7 @@ function action_config_file_save() ]], config_file, config_file)) end - local stat = nixio.fs.stat(config_file) + local stat = fs.stat(config_file) local file_info = {} if stat then file_info = { @@ -3766,4 +3808,397 @@ function action_add_subscription() message = "Failed to add subscription configuration" }) end +end + +function action_upload_overwrite() + local upload = luci.http.formvalue("config_file") + local filename = luci.http.formvalue("filename") + local enable = luci.http.formvalue("enable") + local order = luci.http.formvalue("order") + luci.http.prepare_content("application/json") + if not upload or upload == "" then + luci.http.write_json({status = "error", message = "No file uploaded"}) + return + end + if not filename or filename == "" then + filename = "upload_" .. os.date("%Y%m%d_%H%M%S") + end + if not is_safe_filename(filename) then + luci.http.write_json({status = "error", message = "Invalid filename"}) + return + end + local overwrite_dir = "/etc/openclash/overwrite/" + luci.sys.call("mkdir -p " .. overwrite_dir) + local target_path = overwrite_dir .. filename + if string.len(upload) == 0 then + luci.http.write_json({status = "error", message = "Uploaded file is empty"}) + return + end + local file_size = string.len(upload) + if file_size > 10 * 1024 * 1024 then + luci.http.write_json({status = "error", message = string.format("File size (%s) exceeds 10MB limit", require("luci.openclash").filesize(file_size))}) + return + end + local fp = io.open(target_path, "w") + if fp then + fp:write(upload) + fp:close() + luci.sys.call(string.format("chmod 644 '%s'", target_path)) + luci.sys.call(string.format("chown root:root '%s'", target_path)) + local written_content = fs.readfile(target_path) + if not written_content or string.len(written_content) ~= file_size then + fs.unlink(target_path) + luci.http.write_json({status = "error", message = "File write verification failed"}) + return + end + + local section_name = filename + local found = false + + uci:foreach("openclash", "config_overwrite", function(s) + if s.name == section_name then + found = true + if s.enable == nil or (s.enable ~= nil and enable ~= nil) then + if enable == nil then + enable = 0 + end + uci:set("openclash", s[".name"], "enable", tostring(enable)) + end + if s.order == nil or (s.order ~= nil and s.order ~= order and order ~= nil) then + if order == nil then + local max_order = -1 + uci:foreach("openclash", "config_overwrite", function(s) + local o = tonumber(s.order) + if o and o > max_order then max_order = o end + end) + order = tostring(max_order + 1) + end + uci:set("openclash", s[".name"], "order", order) + else + uci:set("openclash", s[".name"], "order", tonumber(order)) + end + end + end) + if not found then + local sid = uci:add("openclash", "config_overwrite") + uci:set("openclash", sid, "name", section_name) + uci:set("openclash", sid, "type", "file") + if enable ~= nil then + uci:set("openclash", sid, "enable", tostring(enable)) + else + uci:set("openclash", sid, "enable", 0) + end + if order ~= nil then + uci:set("openclash", sid, "order", tostring(order)) + else + local max_order = -1 + uci:foreach("openclash", "config_overwrite", function(s) + local o = tonumber(s.order) + if o and o > max_order then max_order = o end + end) + uci:set("openclash", sid, "order", tostring(max_order + 1)) + end + end + + uci:commit("openclash") + + luci.http.write_json({ + status = "success", + message = "Overwrite file uploaded successfully", + filename = filename, + file_path = target_path, + file_size = file_size, + readable_size = fs.filesize(file_size) + }) + else + luci.http.write_json({status = "error", message = "Failed to save file to disk"}) + end +end + +function action_overwrite_subscribe_info() + local method = luci.http.getenv("REQUEST_METHOD") + local filename = luci.http.formvalue("filename") + local old_filename = luci.http.formvalue("old_filename") + local typ = luci.http.formvalue("type") or "file" + local section_name = nil + local old_section_name = nil + + if filename and not is_safe_filename(filename) then + luci.http.prepare_content("application/json") + luci.http.write_json({status = "error", message = "Invalid filename"}) + return + end + + if filename then + section_name = filename:match("([^/]+)$") + end + if old_filename then + old_section_name = old_filename:match("([^/]+)$") + end + + if method == "GET" then + local result = {} + uci:foreach("openclash", "config_overwrite", function(s) + if s.name then + result[s.name] = { + url = s.url or "", + update_days = s.update_days or "", + update_hour = s.update_hour or "", + order = tonumber(s.order) or 0, + type = s.type or "file", + param = s.param or "", + enable = tonumber(s.enable) or 0 + } + end + end) + luci.http.prepare_content("application/json") + luci.http.write_json({status="success", data=result}) + return + elseif method == "POST" then + if not section_name then + luci.http.status(400, "Missing filename") + return + end + local url = luci.http.formvalue("url") or "" + local update_days = luci.http.formvalue("update_days") or "" + local update_hour = luci.http.formvalue("update_hour") or "" + local order = luci.http.formvalue("order") + local param = luci.http.formvalue("param") or "" + typ = luci.http.formvalue("type") or typ or "file" + local enable = luci.http.formvalue("enable") + + if typ == "http" then + if not url or url == "" then + luci.http.prepare_content("application/json") + luci.http.write_json({ + status = "error", + message = "Subscribe URL cannot be empty" + }) + return + end + local is_valid_url = false + if url:match("^https?://") and not url:find("\n") and not url:find("|") then + is_valid_url = true + end + if not is_valid_url then + luci.http.prepare_content("application/json") + luci.http.write_json({ + status = "error", + message = "Invalid subscribe URL format, only single HTTP/HTTPS link is supported" + }) + return + end + end + + local found = false + if old_section_name and old_section_name ~= "" and old_section_name ~= section_name then + uci:foreach("openclash", "config_overwrite", function(s) + if s.name == old_section_name then + uci:set("openclash", s[".name"], "name", section_name) + uci:set("openclash", s[".name"], "url", url) + uci:set("openclash", s[".name"], "update_days", update_days) + uci:set("openclash", s[".name"], "update_hour", update_hour) + uci:set("openclash", s[".name"], "type", typ) + uci:set("openclash", s[".name"], "param", param) + if s.order == nil or (s.order ~= nil and s.order ~= order and order ~= nil) then + if order == nil then + local max_order = -1 + uci:foreach("openclash", "config_overwrite", function(s) + local o = tonumber(s.order) + if o and o > max_order then max_order = o end + end) + order = tostring(max_order + 1) + end + uci:set("openclash", s[".name"], "order", order) + else + uci:set("openclash", s[".name"], "order", tonumber(order)) + end + if s.enable == nil or (s.enable ~= nil and enable ~= nil) then + if enable == nil then + enable = 0 + end + uci:set("openclash", s[".name"], "enable", tostring(enable)) + end + found = true + end + end) + local overwrite_dir = "/etc/openclash/overwrite/" + local old_file = overwrite_dir .. old_section_name + local new_file = overwrite_dir .. section_name + if fs.access(old_file) and not fs.access(new_file) then + fs.rename(old_file, new_file) + end + uci:commit("openclash") + luci.http.prepare_content("application/json") + luci.http.write_json({status="success"}) + return + end + if not found then + uci:foreach("openclash", "config_overwrite", function(s) + if s.name == section_name then + uci:set("openclash", s[".name"], "url", url) + uci:set("openclash", s[".name"], "update_days", update_days) + uci:set("openclash", s[".name"], "update_hour", update_hour) + uci:set("openclash", s[".name"], "type", typ) + uci:set("openclash", s[".name"], "param", param) + if s.order == nil or (s.order ~= nil and s.order ~= order and order ~= nil) then + if order == nil then + local max_order = -1 + uci:foreach("openclash", "config_overwrite", function(s) + local o = tonumber(s.order) + if o and o > max_order then max_order = o end + end) + order = tostring(max_order + 1) + end + uci:set("openclash", s[".name"], "order", order) + else + uci:set("openclash", s[".name"], "order", tonumber(order)) + end + if s.enable == nil or (s.enable ~= nil and enable ~= nil) then + if enable == nil then + enable = 0 + end + uci:set("openclash", s[".name"], "enable", tostring(enable)) + end + found = true + end + end) + end + if not found then + local sid = uci:add("openclash", "config_overwrite") + uci:set("openclash", sid, "name", section_name) + uci:set("openclash", sid, "url", url) + uci:set("openclash", sid, "update_days", update_days) + uci:set("openclash", sid, "update_hour", update_hour) + uci:set("openclash", sid, "type", typ) + uci:set("openclash", sid, "param", param) + if order == nil then + local max_order = -1 + uci:foreach("openclash", "config_overwrite", function(s) + local o = tonumber(s.order) + if o and o > max_order then max_order = o end + end) + order = tostring(max_order + 1) + else + order = tostring(order) + end + uci:set("openclash", sid, "order", order) + uci:set("openclash", sid, "enable", 0) + end + uci:commit("openclash") + + if typ == "file" then + local overwrite_dir = "/etc/openclash/overwrite/" + local file_path = overwrite_dir .. section_name + if not fs.access(file_path) then + fs.writefile(file_path, "") + end + elseif typ == "http" then + local overwrite_dir = "/etc/openclash/overwrite/" + local file_path = overwrite_dir .. section_name + if url and url ~= "" then + local cmd = string.format('curl -sL --connect-timeout 5 -m 15 "%s" -o "%s"', url, file_path) + local ret = luci.sys.call(cmd) + if not fs.access(file_path) then + fs.writefile(file_path, "") + end + if ret ~= 0 or not fs.access(file_path) or fs.stat(file_path).size == 0 then + luci.http.prepare_content("application/json") + luci.http.write_json({status="error", message="Download failed"}) + return + end + else + if not fs.access(file_path) then + fs.writefile(file_path, "") + end + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json({status="success"}) + return + else + luci.http.status(405, "Method Not Allowed") + end +end + +function action_overwrite_file_list() + local overwrite_files = {} + local custom_file = "/etc/openclash/custom/openclash_custom_overwrite.sh" + + if fs.access(custom_file) then + local stat = fs.stat(custom_file) + if stat and stat.type == "regular" then + table.insert(overwrite_files, { + name = "openclash_custom_overwrite.sh", + path = custom_file, + size = stat.size, + mtime = stat.mtime + }) + end + end + + local overwrite_dir = "/etc/openclash/overwrite/" + if fs.access(overwrite_dir) then + local files = fs.dir(overwrite_dir) + if files then + for _, file in ipairs(files) do + local full_path = overwrite_dir .. file + local stat = fs.stat(full_path) + if stat and stat.type == "regular" then + table.insert(overwrite_files, { + name = file, + path = full_path, + size = stat.size, + mtime = stat.mtime + }) + end + end + end + end + + table.sort(overwrite_files, function(a, b) + return (a.mtime or 0) > (b.mtime or 0) + end) + + luci.http.prepare_content("application/json") + luci.http.write_json({ + overwrite_files = overwrite_files, + total_count = #overwrite_files + }) +end + +function delete_overwrite_file() + local filename = luci.http.formvalue("filename") + if not filename or filename == "" then + luci.http.prepare_content("application/json") + luci.http.write_json({status="error", message="Missing filename"}) + return + end + local overwrite_dir = "/etc/openclash/overwrite/" + local file_path = overwrite_dir .. filename + + if fs.access(file_path) then + fs.unlink(file_path) + end + + uci:foreach("openclash", "config_overwrite", function(s) + if s.name == filename then + uci:delete("openclash", s[".name"]) + end + end) + uci:commit("openclash") + + local order_list = {} + uci:foreach("openclash", "config_overwrite", function(s) + table.insert(order_list, { section = s[".name"], order = tonumber(s.order) or 0 }) + end) + table.sort(order_list, function(a, b) return a.order < b.order end) + for idx, item in ipairs(order_list) do + uci:set("openclash", item.section, "order", tostring(idx - 1)) + end + uci:commit("openclash") + + luci.http.prepare_content("application/json") + luci.http.write_json({status="success"}) end \ No newline at end of file diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/client.lua b/luci-app-openclash/luasrc/model/cbi/openclash/client.lua index d10659be7..5aa5ce418 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/client.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/client.lua @@ -13,7 +13,7 @@ m.reset = false m.submit = false m:section(SimpleSection).template = "openclash/status" -if uci:get("openclash", "config", "dler_token") then +if fs.uci_get("config", "dler_token") then m:append(Template("openclash/dlercloud")) end diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua b/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua index 0e68b6c60..ca914ee4e 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/config-overwrite.lua @@ -29,6 +29,7 @@ s.anonymous = true s:tab("settings", translate("General Settings")) s:tab("dns", "DNS "..translate("Settings")) s:tab("meta", translate("Meta Settings")) +s:tab("smart", translate("Smart Settings")) s:tab("rules", translate("Rules Setting")) s:tab("developer", translate("Developer Settings")) @@ -69,7 +70,7 @@ o:value("http://captive.apple.com/generate_204") o.default = "0" o = s:taboption("settings", Value, "github_address_mod", translate("Github Address Modify")) -o.description = translate("Modify The Github Address In The Config And OpenClash With Proxy(CDN) To Prevent File Download Faild. Format Reference:").." ".."https://ghp.ci/" +o.description = translate("Modify The Github Address In The Config And OpenClash With Proxy(CDN) To Prevent File Download Faild. Format Reference:").." ".."https://ghfast.top/" o:value("0", translate("Disable")) o:value("https://fastly.jsdelivr.net/") o:value("https://testingcf.jsdelivr.net/") @@ -345,6 +346,68 @@ function sniffer_custom.write(self, section, value) end end +-- Smart Settings +o = s:taboption("smart", Flag, "auto_smart_switch", font_red..bold_on..translate("Smart Auto Switch")..bold_off..font_off) +o.description = font_red..bold_on..translate("Auto Switch Url-test and Load-balance Group to Smart Group")..bold_off..font_off +o.default = 0 + +o = s:taboption("smart", ListValue, "smart_strategy", translate("Node Select Strategy")) +o:value("sticky-sessions", translate("Sticky-sessions")) +o:value("round-robin", translate("Round-robin")) +o.default = "sticky-sessions" +o:depends("auto_smart_switch", "1") +o.description = translate("Before Node Data Collect Completely, The Default is Sticky-sessions") + +o = s:taboption("smart", Value, "smart_policy_priority", translate("Policy Priority")) +o.default = "" +o.placeholder = "Premium:0.9;SG:1.3" +o.description = translate("Nodes Weight Priority, <1 Means Lower Priority, >1 Means Higher Priority, The Default is 1, Pattern Support Regex and String") + +o = s:taboption("smart", Flag, "smart_collect", translate("Colletct Training Data")) +o.default = 0 + +o = s:taboption("smart", Value, "smart_collect_size", translate("Data Colletct File Size (MB)")) +o.default = 100 +o:depends("smart_collect", "1") +o.description = translate("Limit The File Size of Collected Data, The Default is 100MB") + +o = s:taboption("smart", Value, "smart_collect_rate", translate("Data Colletct Rate")) +o.default = 1 +o:depends("smart_collect", "1") +o.description = translate("Data Acquisition Rate, Desirable Values are 0-1, The Default is 1") + +o = s:taboption("smart", Flag, "lgbm_auto_update", translate("Auto Update LightGBM Model")) +o.default = 0 + +o = s:taboption("smart", Value, "lgbm_update_interval", translate("Update Interval(hour)")) +o.default = "72" +o:depends("lgbm_auto_update", "1") + +o = s:taboption("smart", Value, "lgbm_custom_url") +o.title = translate("Custom Model URL") +o.rmempty = true +o.description = translate("Custom LightGBM Model URL, Click Button Below To Refresh After Edit") +o:value("https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin", translate("Light Version").." "..translate("(Default)")) +o:value("https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model-middle.bin", translate("Middle Version")) +o:value("https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model-large.bin", translate("Large Version")) +o.default = "https://github.com/vernesong/mihomo/releases/download/LightGBM-Model/Model.bin" +o:depends("lgbm_auto_update", "1") + +o = s:taboption("smart", Button, translate("Model Update")) +o.description = translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/etc/openclash/Model.bin"))..bold_off..font_off +o.title = translate("Update Model") +o.inputtitle = translate("Check And Update") +o.inputstyle = "reload" +o.write = function() + m.uci:set("openclash", "config", "enable", 1) + m.uci:commit("openclash") + SYS.call("/usr/share/openclash/openclash_lgbm.sh >/dev/null 2>&1 &") + HTTP.redirect(DISP.build_url("admin", "services", "openclash")) +end + +o = s:taboption("smart", DummyValue, "flush_smart_cache", translate("Flush Smart Cache")) +o.template = "openclash/flush_smart_cache" + ---- Rules Settings o = s:taboption("rules", Flag, "rule_source", translate("Enable Other Rules")) o.description = translate("Use Other Rules") diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe-edit.lua b/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe-edit.lua index db3482f8c..7d1c33372 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe-edit.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/config-subscribe-edit.lua @@ -59,7 +59,7 @@ end local sub_path = "/tmp/dler_sub" local info, token, get_sub, sub_info -local token = uci:get("openclash", "config", "dler_token") +local token = fs.uci_get("config", "dler_token") if token then get_sub = string.format("curl -sL -H 'Content-Type: application/json' --connect-timeout 2 -d '{\"access_token\":\"%s\"}' -X POST https://dler.cloud/api/v1/managed/clash -o %s", token, sub_path) if not nixio.fs.access(sub_path) then diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/config.lua b/luci-app-openclash/luasrc/model/cbi/openclash/config.lua index 8a19b4877..2a85ec406 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/config.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/config.lua @@ -27,7 +27,7 @@ function IsYmlFile(e) end function default_config_set(f) - local cf = uci:get("openclash", "config", "config_path") + local cf = fs.uci_get("config", "config_path") if cf == "/etc/openclash/config/"..f or not cf or cf == "" or not fs.isfile(cf) then if CHIF == "1" and cf == "/etc/openclash/config/"..f then return @@ -183,7 +183,7 @@ if fs.mtime(BACKUP_FILE) then else e[t].mtime=os.date("%Y-%m-%d %H:%M:%S",a.mtime) end -if uci:get("openclash", "config", "config_path") and string.sub(uci:get("openclash", "config", "config_path"), 23, -1) == e[t].name then +if fs.uci_get("config", "config_path") and string.sub(fs.uci_get("config", "config_path"), 23, -1) == e[t].name then e[t].state=translate("Enabled") else e[t].state=translate("Disabled") @@ -380,7 +380,7 @@ s.description = align_mid..translate("Support syntax check, press").." "..font_g s.anonymous = true s.addremove = false -local conf = uci:get("openclash", "config", "config_path") +local conf = fs.uci_get("config", "config_path") local dconf = "/usr/share/openclash/res/default.yaml" if not conf then conf = "/etc/openclash/config/config.yaml" end local conf_name = fs.basename(conf) diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/rule-providers-settings.lua b/luci-app-openclash/luasrc/model/cbi/openclash/rule-providers-settings.lua index f6217732d..e97329744 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/rule-providers-settings.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/rule-providers-settings.lua @@ -20,7 +20,7 @@ m.description=translate("Attention:").. "
".. "
"..translate("When setting this page, if the groups is empty, please go to the page to add").. "
".. -"
"..translate("Introduction to rule set usage: https://wiki.metacubex.one/config/rule-providers/content/") +"
"..translate("Introduction to rule set usage:").." "..translate("https://wiki.metacubex.one/config/rule-providers/content/").."" function IsRuleFile(e) e=e or"" diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/servers.lua b/luci-app-openclash/luasrc/model/cbi/openclash/servers.lua index 1962f602c..c2f62ab8e 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/servers.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/servers.lua @@ -15,8 +15,8 @@ m.description=translate("Attention:").. "
"..translate("1. Before modifying the configuration file, please click the button below to read the configuration file").. "
"..translate("2. Proxy-providers address can be directly filled in the subscription link").. "
".. -"
"..translate("Introduction to proxy usage: https://wiki.metacubex.one/config/proxies/").. -"
"..translate("Introduction to proxy-provider usage: https://wiki.metacubex.one/config/proxy-providers/") +"
"..translate("Introduction to proxy usage:").." "..translate("https://wiki.metacubex.one/config/proxies/").."".. +"
"..translate("Introduction to proxy-provider usage:").." "..translate("https://wiki.metacubex.one/config/proxy-providers/").."" s = m:section(TypedSection, "openclash") s.anonymous = true diff --git a/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua b/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua index 678cfb5c5..d4f8efa90 100644 --- a/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua +++ b/luci-app-openclash/luasrc/model/cbi/openclash/settings.lua @@ -15,7 +15,7 @@ font_off = [[]] bold_on = [[]] bold_off = [[]] -local op_mode = uci:get("openclash", "config", "operation_mode") +local op_mode = fs.uci_get("config", "operation_mode") if not op_mode then op_mode = "redir-host" end local lan_ip = fs.lanip() m = Map("openclash", translate("Plugin Settings")) @@ -120,10 +120,8 @@ o:value("0", translate("Disable")) o:value("1", translate("Dnsmasq Redirect")) o:value("2", translate("Firewall Redirect")) -if op_mode == "fake-ip" then -o = s:taboption("dns", DummyValue, "flush_fakeip_cache", translate("Flush Fake-IP Cache")) -o.template = "openclash/flush_fakeip_cache" -end +o = s:taboption("dns", DummyValue, "flush_dns_cache", translate("Flush DNS Cache")) +o.template = "openclash/flush_dns_cache" o = s:taboption("dns", Flag, "enable_custom_domain_dns_server", translate("Enable Specify DNS Server")) o.default = 0 @@ -815,7 +813,7 @@ o = s:taboption("rules_update", Button, translate("Other Rules Update")) o:depends("other_rule_auto_update", "1") o.title = translate("Update Other Rules") o.inputtitle = translate("Check And Update") -o.description = translate("Other Rules Update(Only in Use)") +o.description = translate("Other Rules Update(Only in Use)")..", "..translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/usr/share/openclash/res/lhie1.yaml"))..bold_off..font_off o.inputstyle = "reload" o.write = function() m.uci:set("openclash", "config", "enable", 1) @@ -858,6 +856,7 @@ o:depends("geo_auto_update", "1") o = s:taboption("geo_update", Button, translate("GEOIP Update")) o.title = translate("Update GeoIP MMDB") +o.description = translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/etc/openclash/Country.mmdb"))..bold_off..font_off o.inputtitle = translate("Check And Update") o.inputstyle = "reload" o.write = function() @@ -900,6 +899,7 @@ o:depends("geoip_auto_update", "1") o = s:taboption("geo_update", Button, translate("GEOIP Dat Update")) o.title = translate("Update GeoIP Dat") +o.description = translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/etc/openclash/GeoIP.dat"))..bold_off..font_off o.inputtitle = translate("Check And Update") o.inputstyle = "reload" o.write = function() @@ -942,6 +942,7 @@ o:depends("geosite_auto_update", "1") o = s:taboption("geo_update", Button, translate("GEOSITE Update")) o.title = translate("Update GeoSite Database") +o.description = translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/etc/openclash/GeoSite.dat"))..bold_off..font_off o.inputtitle = translate("Check And Update") o.inputstyle = "reload" o.write = function() @@ -984,6 +985,7 @@ o:depends("geoasn_auto_update", "1") o = s:taboption("geo_update", Button, translate("ASN Update")) o.title = translate("Update Geo ASN Database") +o.description = translate("Current Version:").." "..font_green..bold_on..translate(fs.get_resourse_mtime("/etc/openclash/ASN.mmdb"))..bold_off..font_off o.inputtitle = translate("Check And Update") o.inputstyle = "reload" o.write = function() @@ -1231,7 +1233,7 @@ o.title = translate("Account Password") o.password = true o.rmempty = true -if m.uci:get("openclash", "config", "dler_token") then +if fs.uci_get("config", "dler_token") then o = s:taboption("dlercloud", Flag, "dler_checkin") o.title = translate("Checkin") o.default = 0 @@ -1250,20 +1252,20 @@ o.datatype = "uinteger" o.default = "1" o:depends("dler_checkin", "1") o.rmempty = true -o.description = font_green..bold_on..translate("Multiple Must Be a Positive Integer and No More Than 50")..bold_off..font_off +o.description = font_green..bold_on..translate("Multiple Must Be a Positive Integer and No More Than 100")..bold_off..font_off function o.validate(self, value) if tonumber(value) < 1 then return "1" end - if tonumber(value) > 50 then - return "50" + if tonumber(value) > 100 then + return "100" end return value end o = s:taboption("dlercloud", DummyValue, "dler_login", translate("Account Login")) o.template = "openclash/dler_login" -if m.uci:get("openclash", "config", "dler_token") then +if fs.uci_get("config", "dler_token") then o.value = font_green..bold_on..translate("Account logged in")..bold_off..font_off else o.value = font_red..bold_on..translate("Account not logged in")..bold_off..font_off diff --git a/luci-app-openclash/luasrc/openclash.lua b/luci-app-openclash/luasrc/openclash.lua index 277a5c81e..6846bf144 100644 --- a/luci-app-openclash/luasrc/openclash.lua +++ b/luci-app-openclash/luasrc/openclash.lua @@ -272,7 +272,7 @@ function filesize(e) end function lanip() - local lan_int_name = uci:get("openclash", "config", "lan_interface_name") or "0" + local lan_int_name = uci:get("openclash", "@overwrite[0]", "lan_interface_name") or uci:get("openclash", "config", "lan_interface_name") or "0" local lan_ip if lan_int_name == "0" then lan_ip = SYS.exec("uci -q get network.lan.ipaddr 2>/dev/null |awk -F '/' '{print $1}' 2>/dev/null |tr -d '\n'") @@ -286,4 +286,50 @@ function lanip() lan_ip = SYS.exec("ip addr show 2>/dev/null | grep -w 'inet' | grep 'global' | grep 'brd' | grep -Eo 'inet [0-9\.]+' | awk '{print $2}' | head -n 1 | tr -d '\n'") end return lan_ip +end + +function find_case_insensitive_path(path) + local dir = dirname(path) + local base = basename(path) + local files = dir and fs.dir(dir) + if not files then + return nil + end + + for f in files do + if f:lower() == base:lower() then + return dir .. "/" .. f + end + end + return nil +end + +function get_resourse_mtime(path) + local real_path = path + if not fs.access(path) then + local found = find_case_insensitive_path(path) + if found then + real_path = found + else + return "File Not Exist" + end + end + local file = fs.readlink(real_path) or real_path + local model_version = os.date("%Y-%m-%d %H:%M:%S", mtime(real_path)) + if model_version and model_version ~= "" then + return model_version + else + return "Unknown" + end +end + +function uci_get(section, key) + local val + if section == "config" then + val = uci:get("openclash", "@overwrite[0]", key) + end + if val == nil then + val = uci:get("openclash", section, key) + end + return val end \ No newline at end of file diff --git a/luci-app-openclash/luasrc/view/openclash/config_edit.htm b/luci-app-openclash/luasrc/view/openclash/config_edit.htm index 913ce6a1b..158dd6a6c 100644 --- a/luci-app-openclash/luasrc/view/openclash/config_edit.htm +++ b/luci-app-openclash/luasrc/view/openclash/config_edit.htm @@ -1,65 +1,51 @@
-
-
+
+
<%:File Edit%>: @@ -483,6 +582,10 @@
+ +