diff --git a/application/qmodem/files/usr/share/qmodem/modem_ctrl.sh b/application/qmodem/files/usr/share/qmodem/modem_ctrl.sh index 51441da5..1679b526 100755 --- a/application/qmodem/files/usr/share/qmodem/modem_ctrl.sh +++ b/application/qmodem/files/usr/share/qmodem/modem_ctrl.sh @@ -61,7 +61,7 @@ get_sms(){ if [ ! -f $cache_file ] || [ $(($current_time - $file_time)) -gt $cache_timeout ]; then touch $cache_file #sms_tool_q -d $at_port -j recv > $cache_file - tom_modem $use_ubus_flag -d $at_port -o r > $cache_file + tom_modem $use_ubus_flag -d "$at_port" -o r > $cache_file echo $(cat $cache_file ; json_dump) | jq -s 'add' else echo $(cat $cache_file ; json_dump) | jq -s 'add' @@ -158,7 +158,7 @@ case $method in index=$3 [ -n "$sms_at_port" ] && at_port=$sms_at_port for i in $index; do - tom_modem $use_ubus_flag -d $at_port -o d -i $i + tom_modem $use_ubus_flag -d "$at_port" -o d -i "$i" touch /tmp/cache_sms_$2 if [ "$?" == 0 ]; then json_add_string status "1" @@ -243,7 +243,7 @@ case $method in "send_at") cmd=$(echo "$3" | jq -r '.at') port=$(echo "$3" | jq -r '.port') - res=$(at $port $cmd) + res=$(at "$port" "$cmd") json_add_object at_cfg if [ "$?" == 0 ]; then json_add_string status "1" @@ -256,7 +256,7 @@ case $method in "send_raw_pdu") cmd=$3 [ -n "$sms_at_port" ] && at_port=$sms_at_port - res=$(tom_modem $use_ubus_flag -d $at_port -o s -p "$cmd") + res=$(tom_modem $use_ubus_flag -d "$at_port" -o s -p "$cmd") json_select result if [ "$?" == 0 ]; then json_add_string status "1" @@ -271,7 +271,7 @@ case $method in phone_number=$(echo $cmd_json | jq -r '.phone_number') message_content=$(echo $cmd_json | jq -r '.message_content') [ -n "$sms_at_port" ] && at_port=$sms_at_port - sms_tool_q -d $at_port send "$phone_number" "$message_content" > /dev/null + sms_tool_q -d "$at_port" send "$phone_number" "$message_content" > /dev/null json_select result if [ "$?" == 0 ]; then json_add_string status "1" diff --git a/application/qmodem/files/usr/share/qmodem/modem_util.sh b/application/qmodem/files/usr/share/qmodem/modem_util.sh index 01a9011c..4cd4a632 100755 --- a/application/qmodem/files/usr/share/qmodem/modem_util.sh +++ b/application/qmodem/files/usr/share/qmodem/modem_util.sh @@ -4,28 +4,28 @@ at() { - local at_port=$1 + local at_port="$1" local new_str="${2/[$]/$}" local atcmd="${new_str/\"/\"}" [ "$clear_buffer" == "1" ] && options="$options -M" #过滤空行 if [ "$(uci get qmodem.main.at_tool 2>/dev/null)" == "1" ]; then - sms_tool_q -d $at_port at "$atcmd" + sms_tool_q -d "$at_port" at "$atcmd" else - tom_modem $use_ubus_flag -d $at_port -o a -c "$atcmd" $options + tom_modem $use_ubus_flag -d "$at_port" -o a -c "$atcmd" $options fi } fastat() { - local at_port=$1 + local at_port="$1" local new_str="${2/[$]/$}" local atcmd="${new_str/\"/\"}" #过滤空行 if [ "$(uci get qmodem.main.at_tool 2>/dev/null)" == "1" ]; then - sms_tool_q -t 1 -d $at_port at "$atcmd" + sms_tool_q -t 1 -d "$at_port" at "$atcmd" else - tom_modem -d $at_port -o a -c "$atcmd" -t 1 + tom_modem -d "$at_port" -o a -c "$atcmd" -t 1 fi } diff --git a/luci/luci-app-qmodem-hc/luasrc/controller/qmodem_hc.lua b/luci/luci-app-qmodem-hc/luasrc/controller/qmodem_hc.lua index 8446d70d..2bb33cb0 100644 --- a/luci/luci-app-qmodem-hc/luasrc/controller/qmodem_hc.lua +++ b/luci/luci-app-qmodem-hc/luasrc/controller/qmodem_hc.lua @@ -56,6 +56,11 @@ function setSIM() local sim_gpio = "/sys/class/gpio/sim/value" local modem_gpio = "/sys/class/gpio/4g/value" local sim_slot = http.formvalue("slot") + if sim_slot ~= "SIM1" and sim_slot ~= "SIM2" then + luci.http.status(400, "Bad Request") + return writeJsonResponse("Invalid", "Invalid") + end + local pre_detect = getSimSlot(sim_gpio) local reset_module = 1 @@ -63,18 +68,18 @@ function setSIM() reset_module = 0 end if sim_slot == "SIM1" then - sysfs_cmd = "echo 1 >"..sim_gpio + sysfs_value = "1" fw_setenv_cmd = "fw_setenv sim2" elseif sim_slot == "SIM2" then - sysfs_cmd = "echo 0 >"..sim_gpio + sysfs_value = "0" fw_setenv_cmd = "fw_setenv sim2 1" end - shell(sysfs_cmd) + fs.writefile(sim_gpio, sysfs_value) shell(fw_setenv_cmd) if reset_module == 1 then - shell("echo 0 >"..modem_gpio) + fs.writefile(modem_gpio, "0") os.execute("sleep 1") - shell("echo 1 >"..modem_gpio) + fs.writefile(modem_gpio, "1") end local current_slot = getSimSlot(sim_gpio) local nextboot_slot = getNextBootSlot() diff --git a/luci/luci-app-qmodem-next/htdocs/luci-static/resources/qmodem/sms-pdu.js b/luci/luci-app-qmodem-next/htdocs/luci-static/resources/qmodem/sms-pdu.js index 31972252..8123f20f 100644 --- a/luci/luci-app-qmodem-next/htdocs/luci-static/resources/qmodem/sms-pdu.js +++ b/luci/luci-app-qmodem-next/htdocs/luci-static/resources/qmodem/sms-pdu.js @@ -426,8 +426,8 @@ class LuciTable{ var left = data.left; var right = data.right; //clear the row - this.rows[index].left.innerHTML = ""; - this.rows[index].right.innerHTML = ""; + this.rows[index].left.textContent = ""; + this.rows[index].right.textContent = ""; //set the row this.rows[index].left.appendChild(left); this.rows[index].right.appendChild(right); @@ -441,8 +441,8 @@ class LuciTable{ set title(value){ - this.legend.innerHTML = value; - this.title_span.innerHTML = value; + this.legend.textContent = value; + this.title_span.textContent = value; } set object_data(value){ @@ -476,8 +476,8 @@ class LuciTable{ } var index = 0; for (var key in value) { - this.rows[index].left.innerHTML = key; - this.rows[index].right.innerHTML = value[key]; + this.rows[index].left.textContent = key; + this.rows[index].right.textContent = value[key]; index++; } } diff --git a/luci/luci-app-qmodem-next/root/usr/share/rpcd/ucode/qmodem_sms b/luci/luci-app-qmodem-next/root/usr/share/rpcd/ucode/qmodem_sms index 182073e5..7947140b 100755 --- a/luci/luci-app-qmodem-next/root/usr/share/rpcd/ucode/qmodem_sms +++ b/luci/luci-app-qmodem-next/root/usr/share/rpcd/ucode/qmodem_sms @@ -7,6 +7,60 @@ import { cursor } from 'uci'; const TOM_MODEM_PATH = '/usr/bin/tom_modem'; const DEFAULT_SMS_DB_DIR = '/etc/qmodem'; +function shellQuote(value) { + value = `${value ?? ''}`; + let quoted = "'"; + for (let i = 0; i < length(value); i++) { + let ch = substr(value, i, 1); + quoted += ch == "'" ? "'\\''" : ch; + } + return quoted + "'"; +} + +function hasOnlyChars(value, allowed) { + value = `${value ?? ''}`; + for (let i = 0; i < length(value); i++) { + if (index(allowed, substr(value, i, 1)) < 0) + return false; + } + return true; +} + +function isSafeToken(value) { + value = `${value ?? ''}`; + if (!value || length(value) > 64) + return false; + return hasOnlyChars(value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'); +} + +function isSafePath(value) { + value = `${value ?? ''}`; + if (!value || length(value) > 128 || substr(value, 0, 1) != '/') + return false; + + if (index(value, '..') >= 0) + return false; + return hasOnlyChars(value, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789/_-.'); +} + +function isSafePdu(value) { + value = `${value ?? ''}`; + if (!value || length(value) > 2048) + return false; + return hasOnlyChars(value, '0123456789ABCDEFabcdef'); +} + +function isNonNegativeInteger(value) { + value = `${value ?? ''}`; + if (!value || length(value) > 10) + return false; + return hasOnlyChars(value, '0123456789'); +} + +function isSmsStorage(value) { + return value == 'ME' || value == 'SM' || value == 'MT'; +} + // Initialize SMS database function initSmsDb(db_path, config_section) { let db_dir = db_path; @@ -17,7 +71,7 @@ function initSmsDb(db_path, config_section) { stat(db_dir); } catch (e) { try { - system(`mkdir -p ${db_dir}`); + system(`mkdir -p ${shellQuote(db_dir)}`); } catch (err) { warn(`Failed to create directory ${db_dir}: ${err}\n`); return false; @@ -59,7 +113,7 @@ function initReceivedSmsDb(db_path, config_section) { stat(db_dir); } catch (e) { try { - system(`mkdir -p ${db_dir}`); + system(`mkdir -p ${shellQuote(db_dir)}`); } catch (err) { warn(`Failed to create directory ${db_dir}: ${err}\n`); return false; @@ -185,6 +239,9 @@ function writeReceivedSmsDb(db_path, config_section, data) { // Get modem configuration from UCI function getModemConfig(config_section) { + if (!isSafeToken(config_section)) + return null; + let ctx = cursor(); if (!ctx) return null; @@ -198,6 +255,9 @@ function getModemConfig(config_section) { let use_ubus = cfg.use_ubus == '1'; let sms_db_path = cfg.sms_db_path || DEFAULT_SMS_DB_DIR; let sms_auto_delete_from_sim = cfg.sms_auto_delete_from_sim != '0'; // Default to true + + if (!isSafePath(at_port) || !isSafePath(sms_db_path)) + return null; return { at_port: at_port, @@ -209,18 +269,30 @@ function getModemConfig(config_section) { // Execute tom_modem command function execTomModem(at_port, use_ubus, operation, params) { + if (operation != 'r' && operation != 's' && operation != 'd') + return null; + + if (!isSafePath(at_port)) + return null; + let cmd = TOM_MODEM_PATH; if (use_ubus) cmd += ' -u'; - cmd += ` -d "${at_port}" -o ${operation}`; + cmd += ` -d ${shellQuote(at_port)} -o ${operation}`; - if (params?.pdu) - cmd += ` -p "${params.pdu}"`; + if (params?.pdu) { + if (!isSafePdu(params.pdu)) + return null; + cmd += ` -p ${shellQuote(params.pdu)}`; + } - if (params?.index != null) + if (params?.index != null) { + if (!isNonNegativeInteger(params.index)) + return null; cmd += ` -i ${params.index}`; + } try { let proc = popen(cmd, 'r'); @@ -248,23 +320,15 @@ function execTomModem(at_port, use_ubus, operation, params) { // Execute AT command directly via tom_modem function execAtCommand(at_port, use_ubus, at_cmd) { + if (!isSafePath(at_port)) + return null; + let cmd = TOM_MODEM_PATH; if (use_ubus) cmd += ' -u'; - // Use single quotes to wrap AT command to preserve internal double quotes - // Replace any single quotes in the AT command with '\'' to escape them - let safe_cmd = ''; - for (let i = 0; i < length(at_cmd); i++) { - let ch = substr(at_cmd, i, 1); - if (ch == "'") - safe_cmd += "'\\''"; - else - safe_cmd += ch; - } - - cmd += ` -d '${at_port}' -o a -c '${safe_cmd}'`; + cmd += ` -d ${shellQuote(at_port)} -o a -c ${shellQuote(at_cmd)}`; try { let proc = popen(cmd, 'r'); @@ -737,8 +801,6 @@ return { let conversations = groupByConversation(all_messages); return { - modem_config: config, - received_from_sim: received_from_sim, conversations: conversations, total: length(all_messages) }; @@ -1213,6 +1275,9 @@ return { if (!mem1 || !mem2) return { error: 'Missing mem1 or mem2 parameter' }; + + if (!isSmsStorage(mem1) || !isSmsStorage(mem2) || (mem3 && mem3 != 'Loading' && !isSmsStorage(mem3))) + return { error: 'Invalid SMS storage parameter' }; // Build AT+CPMS command let at_cmd = `AT+CPMS="${mem1}","${mem2}"`; @@ -1274,9 +1339,9 @@ return { let config = getModemConfig(config_section); if (!config) return { error: 'Failed to get modem configuration' }; - + let index = request.args.index; - if (index == null || index < 0) + if (!isNonNegativeInteger(index)) return { error: 'Invalid SMS index' }; // Delete SMS from SIM card diff --git a/luci/luci-app-qmodem-sms/luasrc/controller/qmodem_sms.lua b/luci/luci-app-qmodem-sms/luasrc/controller/qmodem_sms.lua index f5432baf..35a2d161 100644 --- a/luci/luci-app-qmodem-sms/luasrc/controller/qmodem_sms.lua +++ b/luci/luci-app-qmodem-sms/luasrc/controller/qmodem_sms.lua @@ -2,6 +2,7 @@ module("luci.controller.qmodem_sms", package.seeall) local http = require "luci.http" local fs = require "nixio.fs" local json = require("luci.jsonc") +local util = require "luci.util" local modem_ctrl = "/usr/share/qmodem/modem_ctrl.sh " function shell(command) @@ -11,6 +12,23 @@ function shell(command) return odp end +local function valid_token(value) + return value and value:match("^[A-Za-z0-9_-]+$") ~= nil +end + +local function valid_index(value) + return value and value:match("^[0-9 ]+$") ~= nil +end + +local function valid_pdu(value) + return value and value:match("^[A-Fa-f0-9]+$") ~= nil +end + +local function write_error(message) + http.prepare_content("application/json") + http.write(json.stringify({ status = "0", error = message })) +end + function index() --sim卡配置 entry({"admin", "modem", "qmodem", "modem_sms"},template("modem_sms/modem_sms"), luci.i18n.translate("SMS"), 11).leaf = true @@ -23,31 +41,52 @@ end function getSMS() local cfg_id = http.formvalue("cfg") - response = shell(modem_ctrl .. "get_sms " .. cfg_id) + if not valid_token(cfg_id) then + return write_error("Invalid config section") + end + + response = shell(modem_ctrl .. "get_sms " .. util.shellquote(cfg_id)) http.prepare_content("application/json") http.write(response) end function sendSMS() local cfg_id = http.formvalue("cfg") + if not valid_token(cfg_id) then + return write_error("Invalid config section") + end + local pdu = http.formvalue("pdu") if pdu then - response = shell(modem_ctrl .. "send_raw_pdu " .. cfg_id .. " \"" .. pdu .. "\"") + if not valid_pdu(pdu) then + return write_error("Invalid PDU") + end + response = shell(modem_ctrl .. "send_raw_pdu " .. util.shellquote(cfg_id) .. " " .. util.shellquote(pdu)) else - local phone_number = http.formvalue("phone_number") - local message_content = http.formvalue("message_content") - json_cmd = string.format('{\\"phone_number\\":\\"%s\\",\\"message_content\\":\\"%s\\"}', phone_number, message_content) - response = shell(modem_ctrl .. "send_sms " .. cfg_id .." \"".. json_cmd .. "\"") + local phone_number = http.formvalue("phone_number") or "" + local message_content = http.formvalue("message_content") or "" + local json_cmd = json.stringify({ + phone_number = phone_number, + message_content = message_content + }) + response = shell(modem_ctrl .. "send_sms " .. util.shellquote(cfg_id) .. " " .. util.shellquote(json_cmd)) end http.prepare_content("application/json") - http.write(response) + http.write(response) end function delSMS() local cfg_id = http.formvalue("cfg") local index = http.formvalue("index") - response = shell(modem_ctrl .. "delete_sms " .. cfg_id .. " \"" ..index.."\"") + if not valid_token(cfg_id) then + return write_error("Invalid config section") + end + if not valid_index(index) then + return write_error("Invalid SMS index") + end + + response = shell(modem_ctrl .. "delete_sms " .. util.shellquote(cfg_id) .. " " .. util.shellquote(index)) http.prepare_content("application/json") http.write(response) end diff --git a/luci/luci-app-qmodem-sms/luasrc/view/modem_sms/modem_sms.htm b/luci/luci-app-qmodem-sms/luasrc/view/modem_sms/modem_sms.htm index 09761535..2efc222a 100644 --- a/luci/luci-app-qmodem-sms/luasrc/view/modem_sms/modem_sms.htm +++ b/luci/luci-app-qmodem-sms/luasrc/view/modem_sms/modem_sms.htm @@ -426,8 +426,8 @@ var left = data.left; var right = data.right; //clear the row - this.rows[index].left.innerHTML = ""; - this.rows[index].right.innerHTML = ""; + this.rows[index].left.textContent = ""; + this.rows[index].right.textContent = ""; //set the row this.rows[index].left.appendChild(left); this.rows[index].right.appendChild(right); @@ -441,8 +441,8 @@ set title(value){ - this.legend.innerHTML = value; - this.title_span.innerHTML = value; + this.legend.textContent = value; + this.title_span.textContent = value; } set object_data(value){ @@ -476,8 +476,8 @@ } var index = 0; for (var key in value) { - this.rows[index].left.innerHTML = key; - this.rows[index].right.innerHTML = value[key]; + this.rows[index].left.textContent = key; + this.rows[index].right.textContent = value[key]; index++; } } @@ -556,7 +556,7 @@ const createOption = (value, text, disabled = false, selected = false) => { const opt = document.createElement('option'); opt.value = value; - opt.innerHTML = text; + opt.textContent = text; opt.disabled = disabled; opt.selected = selected; return opt; @@ -618,7 +618,7 @@ warn_msg(msg,timeout){ this.warn_msg_box.style.display = ""; this.warn_msg_box.classList.add("alert-warning"); - this.warn_msg_box.firstChild.innerHTML = msg; + this.warn_msg_box.firstChild.textContent = msg; setTimeout(()=>{ this.warn_msg_box.style.display = "none"; this.warn_msg_box.classList.remove("alert-warning"); @@ -628,7 +628,7 @@ log_msg(msg,timeout){ this.warn_msg_box.style.display = ""; this.warn_msg_box.classList.add("alert-info"); - this.warn_msg_box.firstChild.innerHTML = msg; + this.warn_msg_box.firstChild.textContent = msg; setTimeout(()=>{ this.warn_msg_box.style.display = "none"; this.warn_msg_box.classList.remove("alert-info"); @@ -889,8 +889,8 @@ } else { storage.value = "Loading"; } - this[mtOpt].innerHTML = mt + me_message_text; - this[smOpt].innerHTML = sm + sm_message_text; + this[mtOpt].textContent = mt + me_message_text; + this[smOpt].textContent = sm + sm_message_text; }; const me_message_text = sms_capabilities.ME.used @@ -917,7 +917,7 @@ this.selector.appendChild(option); } option.value = value[i].value; - option.innerHTML = value[i].name; + option.textContent = value[i].name; } else{ @@ -969,11 +969,11 @@ }); }); sender_strong = document.createElement('strong'); - sender_strong.innerHTML = `<%:Sender%>: ${sender}`; + sender_strong.textContent = `<%:Sender%>: ${sender}`; timestamp_strong = document.createElement('strong'); - timestamp_strong.innerHTML = `<%:Timestamp%>: ${timestamp}`; + timestamp_strong.textContent = `<%:Timestamp%>: ${timestamp}`; content_strong = document.createElement('strong'); - content_strong.innerHTML = `<%:Content%>: ${content}`; + content_strong.textContent = `<%:Content%>: ${content}`; left.appendChild(sender_strong); left.appendChild(document.createElement('br')); left.appendChild(timestamp_strong); @@ -982,7 +982,7 @@ right.appendChild(content_strong); if (part != null) { part_strong = document.createElement('strong'); - part_strong.innerHTML = `(${part}/${total})`; + part_strong.textContent = `(${part}/${total})`; right.appendChild(document.createElement('br')); right.appendChild(part_strong); } diff --git a/luci/luci-app-qmodem/luasrc/controller/qmodem.lua b/luci/luci-app-qmodem/luasrc/controller/qmodem.lua index fa419415..d38d213a 100644 --- a/luci/luci-app-qmodem/luasrc/controller/qmodem.lua +++ b/luci/luci-app-qmodem/luasrc/controller/qmodem.lua @@ -4,10 +4,61 @@ module("luci.controller.qmodem", package.seeall) local http = require "luci.http" local fs = require "nixio.fs" local json = require("luci.jsonc") +local util = require "luci.util" uci = luci.model.uci.cursor() local script_path="/usr/share/qmodem/" local run_path="/tmp/run/qmodem/" local modem_ctrl = "/usr/share/qmodem/modem_ctrl.sh " +local allowed_modem_actions = { + base_info = true, + cell_info = true, + clear_stats = true, + clear_dial_log = true, + delete_sms = true, + do_reboot = true, + get_at_cfg = true, + get_copyright = true, + get_current_band = true, + get_current_band_capabilities = true, + get_disabled_features = true, + get_dns = true, + get_imei = true, + get_lockband = true, + get_mode = true, + get_neighborcell = true, + get_network_prefer = true, + get_reboot_caps = true, + get_stats = true, + get_sms = true, + info = true, + network_info = true, + send_at = true, + send_raw_pdu = true, + send_sms = true, + set_imei = true, + set_lockband = true, + set_mode = true, + set_neighborcell = true, + set_network_prefer = true, + set_sms_storage = true, + sim_info = true, + get_sim_switch_capabilities = true, + get_sim_slot = true, + set_sim_slot = true +} + +local function valid_token(value) + return value and value:match("^[A-Za-z0-9_-]+$") ~= nil +end + +local function valid_path(value) + return value and value:match("^/[A-Za-z0-9_/%-%.]+$") ~= nil and not value:match("%.%.") +end + +local function write_json_error(message) + luci.http.prepare_content("application/json") + luci.http.write_json({ error = message }) +end function index() if not nixio.fs.access("/etc/config/qmodem") then @@ -72,10 +123,16 @@ function modemCtrl() local cfg_id = http.formvalue("cfg") local params = http.formvalue("params") local translate = http.formvalue("translate") + if not allowed_modem_actions[action] then + return write_json_error("Invalid action") + end + if not valid_token(cfg_id) then + return write_json_error("Invalid config section") + end if params then - result = shell(modem_ctrl..action.." "..cfg_id.." ".."\""..params.."\"") + result = shell(modem_ctrl..util.shellquote(action).." "..util.shellquote(cfg_id).." "..util.shellquote(params)) else - result = shell(modem_ctrl..action.." "..cfg_id) + result = shell(modem_ctrl..util.shellquote(action).." "..util.shellquote(cfg_id)) end if translate == "1" then modem_more_info = json.parse(result) @@ -93,7 +150,10 @@ end at_command AT命令 ]] function at(at_port,at_command) - local command="source "..script_path.."modem_util.sh && at "..at_port.." "..at_command + if not valid_path(at_port) then + return "" + end + local command="source "..util.shellquote(script_path.."modem_util.sh").." && at "..util.shellquote(at_port).." "..util.shellquote(at_command or "") local result=shell(command) result=string.gsub(result, "\r", "") return result @@ -116,7 +176,7 @@ function getOverviews() return end --模组信息部分 - cmd = modem_ctrl.."base_info "..section_name + cmd = modem_ctrl.."base_info "..util.shellquote(section_name) result = shell(cmd) json_result = json.parse(result) or "{}" modem_info = json_result["modem_info"] @@ -213,7 +273,11 @@ function sendATCommand() local response={} if at_port and at_command then - response["response"]=at(at_port,at_command) + if valid_path(at_port) then + response["response"]=at(at_port,at_command) + else + response["error"]="Invalid AT port" + end response["time"]=os.date("%Y-%m-%d %H:%M:%S") end diff --git a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_config.lua b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_config.lua index 412bd7d0..fa80f8cf 100644 --- a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_config.lua +++ b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_config.lua @@ -1,6 +1,11 @@ local dispatcher = require "luci.dispatcher" local uci = require "luci.model.uci".cursor() local http = require "luci.http" +local fs = require "nixio.fs" + +local function safe_dir(path) + return fs.dir(path) or function() return nil end +end m = Map("qmodem", translate("Modem Configuration")) m.redirect = dispatcher.build_url("admin", "modem", "qmodem","dial_overview") @@ -81,11 +86,9 @@ bridge_mode.default = "0" bridge_port = s:taboption("advanced", Value, "bridge_port", translate("Bridge Port")) bridge_port.description = translate("Device-level bridge port for passthrough. If set, it overrides the slot default bridge port.") bridge_port.rmempty = true -local bridge_ports = io.popen("ls /sys/class/net/") -for line in bridge_ports:lines() do +for line in safe_dir("/sys/class/net/") do bridge_port:value(line, line) end -bridge_ports:close() do_not_add_dns = s:taboption("advanced", Flag, "do_not_add_dns", translate("Do Not modify resolv.conf")) do_not_add_dns.description = translate("quectel-CM will append the DNS server to the resolv.conf file by default.if you do not want to modify the resolv.conf file, please check this option.") diff --git a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_overview.lua b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_overview.lua index f6f2c5be..ae127fce 100644 --- a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_overview.lua +++ b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/dial_overview.lua @@ -1,5 +1,6 @@ local d = require "luci.dispatcher" local sys = require "luci.sys" +local util = require "luci.util" m = Map("qmodem") m.title = translate("Dial Overview") @@ -31,7 +32,7 @@ o.rmempty = false restart_btn = s:option(Button, "_redial", translate("ReDial")) restart_btn.inputstyle = "remove" function restart_btn.write(self, section) - sys.call("/etc/init.d/qmodem_network redial "..section.." > /dev/null 2>&1") + sys.call("/etc/init.d/qmodem_network redial "..util.shellquote(section).." > /dev/null 2>&1") luci.http.redirect(d.build_url("admin", "modem", "qmodem", "dial_overview")) end @@ -82,7 +83,7 @@ remove_btn = s:option(Button, "_remove", translate("Remove Modem")) remove_btn.inputstyle = "remove" function remove_btn.write(self, section) local shell - shell="/usr/share/qmodem/modem_scan.sh remove "..section + shell="/usr/share/qmodem/modem_scan.sh remove "..util.shellquote(section) luci.sys.call(shell) --refresh the page luci.http.redirect(d.build_url("admin", "modem", "qmodem", "dial_overview")) diff --git a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/modem_config.lua b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/modem_config.lua index 9e111bd8..183516be 100644 --- a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/modem_config.lua +++ b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/modem_config.lua @@ -1,15 +1,20 @@ local modem_cfg = require "luci.model.cbi.qmodem.modem_cfg" +local fs = require "nixio.fs" + +local function safe_dir(path) + return fs.dir(path) or function() return nil end +end -- Helper function to load slot paths local function load_slots(path, exclude_pattern) local slots = {} - local handle = io.popen("ls " .. path) - for line in handle:lines() do - if not exclude_pattern or not line:match(exclude_pattern) then - table.insert(slots, line) + for line in safe_dir(path) do + if line ~= "." and line ~= ".." then + if not exclude_pattern or not line:match(exclude_pattern) then + table.insert(slots, line) + end end end - handle:close() return slots end diff --git a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/settings.lua b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/settings.lua index d9f47c1d..8ca40753 100644 --- a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/settings.lua +++ b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/settings.lua @@ -1,5 +1,11 @@ local sys = require "luci.sys" local d = require "luci.dispatcher" +local fs = require "nixio.fs" + +local function safe_dir(path) + return fs.dir(path) or function() return nil end +end + m = Map("qmodem") m.title = translate("QModem Setting") @@ -121,20 +127,16 @@ s.template = "cbi/tblsection" s.template_addremove = "qmodem/modem_config_add" s.extedit = d.build_url("admin", "modem", "qmodem", "modem_config", "%s") s.sectionhead = translate("Config Name") -local pcie_slots = io.popen("ls /sys/bus/pci/devices/") local pcie_slot_list = {} -for line in pcie_slots:lines() do +for line in safe_dir("/sys/bus/pci/devices/") do table.insert(pcie_slot_list, line) end -pcie_slots:close() -local usb_slots = io.popen("ls /sys/bus/usb/devices/") local usb_slot_list = {} -for line in usb_slots:lines() do +for line in safe_dir("/sys/bus/usb/devices/") do if not line:match("usb%d+") then table.insert(usb_slot_list, line) end end -usb_slots:close() local avalibale_name_list = {} for i,v in ipairs(pcie_slot_list) do local uci_name = v:gsub("%.", "_"):gsub(":", "_"):gsub("-", "_") diff --git a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/slot_config.lua b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/slot_config.lua index f3e12308..81b731df 100644 --- a/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/slot_config.lua +++ b/luci/luci-app-qmodem/luasrc/model/cbi/qmodem/slot_config.lua @@ -1,3 +1,9 @@ +local fs = require "nixio.fs" + +local function safe_dir(path) + return fs.dir(path) or function() return nil end +end + m = Map("qmodem", translate("Slot Configuration")) m.redirect = luci.dispatcher.build_url("admin", "modem", "qmodem","settings") @@ -10,11 +16,9 @@ slot_type:value("pcie", translate("PCIE")) slot = s:option(Value, "slot", translate("Slot ID")) -local pcie_slots = io.popen("ls /sys/bus/pci/devices/") -for line in pcie_slots:lines() do +for line in safe_dir("/sys/bus/pci/devices/") do slot:value(line,line.."[pcie]") end -pcie_slots:close() @@ -24,8 +28,7 @@ sim_led.rmempty = true net_led = s:option(Value, "net_led", translate("NET LED")) net_led.rmempty = true -local leds = io.popen("ls /sys/class/leds/") -for line in leds:lines() do +for line in safe_dir("/sys/class/leds/") do net_led:value(line,line) sim_led:value(line,line) end @@ -33,20 +36,16 @@ end ethernet_5g = s:option(Value, "ethernet_5g", translate("Enable 5G Ethernet")) ethernet_5g.rmempty = true ethernet_5g.description = translate("For 5G modules using the Ethernet PHY connection, please specify the network interface name. (e.g., eth0, eth1)") -local net = io.popen("ls /sys/class/net/") -for line in net:lines() do +for line in safe_dir("/sys/class/net/") do ethernet_5g:value(line,line) end -net:close() bridge_port = s:option(Value, "bridge_port", translate("Bridge Port")) bridge_port.rmempty = true bridge_port.description = translate("Default bridge port for passthrough. Device-level bridge_port overrides this slot default.") -local bridge_net = io.popen("ls /sys/class/net/") -for line in bridge_net:lines() do +for line in safe_dir("/sys/class/net/") do bridge_port:value(line, line) end -bridge_net:close() default_alias = s:option(Value, "alias", translate("Default Alias")) default_alias.description = translate("After setting this option, the first module loaded into this slot will automatically be assigned this default alias.") @@ -57,8 +56,7 @@ associated_usb = s:option(Value, "associated_usb", translate("Associated USB")) associated_usb.rmempty = true associated_usb.description = translate("For M.2 slots with both PCIe and USB support, specify the associated USB port (for ttyUSB access)") associated_usb:depends("type", "pcie") -local usb_slots = io.popen("ls /sys/bus/usb/devices/") -for line in usb_slots:lines() do +for line in safe_dir("/sys/bus/usb/devices/") do if not line:match("usb%d+") then slot:value(line,line.."[usb]") associated_usb:value(line,line) @@ -78,5 +76,4 @@ gpio_down = s:option(Value,"gpio_down",translate("GPIO Down Value")) gpio_up = s:option(Value,"gpio_up",translate("GPIO Up Value")) -usb_slots:close() return m