added advance settings functionality

This commit is contained in:
Russel Yasol
2024-10-03 22:18:49 +08:00
parent f93a4d8082
commit 46c1d92f90
6 changed files with 892 additions and 38 deletions

View File

@@ -26,6 +26,8 @@
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/advance/at-terminal.js"></script>
<script src="/js/advance/ttl-control.js"></script>
<script src="/js/advance/fetch-current.settings.js"></script>
<script>
(function () {
@@ -222,46 +224,72 @@
<div class="card-content">
<div class="fixed-grid has-1-cols">
<div class="grid is-gap-5">
<div class="cell">
<div class="cell advanced-settings">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid">
<div class="cell">
<div class="field">
<label class="label">IP Passthrough Mode</label>
<p class="control has-icons-left">
<span class="select">
<select>
<option selected>
Select IP Passthrough Mode
</option>
<option>Disable</option>
<option>ETH Only</option>
<option>USB Only</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-ethernet"></i>
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
</p>
<div class="cell is-col-span-2 is-col-span-1-mobile">
<div class="columns">
<div class="column">
<div class="field">
<label class="label">IP Passthrough Mode</label>
<p class="control has-icons-left">
<span class="select">
<select id="ip-passthrough-mode">
<option value="placeholder" selected>
Select IP Passthrough Mode
</option>
<option value="Disabled">Disabled</option>
<option value="ETH Only">ETH Only</option>
<option value="USB Only">USB Only</option>
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-ethernet"></i>
</span>
</p>
<p class="help">
This will reboot the device to apply changes.
</p>
</div>
</div>
<div class="column">
<div class="field">
<label class="label">Connected Devices MAC</label>
<p class="control has-icons-left">
<span class="select">
<select id="connected-devices">
<option selected>
Select Device MAC
</option>
<!-- Populate the options here -->
</select>
</span>
<span class="icon is-small is-left">
<i class="fas fa-laptop"></i>
</span>
</p>
<p class="help">
Selecting a device first before enabling.
</p>
</div>
</div>
</div>
</div>
<div class="cell">
<div class="cell advanced-settings">
<div class="field">
<label class="label">USB Modem Protocol</label>
<p class="control has-icons-left">
<span class="select">
<select>
<select id="usb-modem-protocol">
<option selected>
Select USB Modem Protocol
</option>
<option>RMNET</option>
<option>ECM (Recommended)</option>
<option>MBIM</option>
<option>RNDIS</option>
<option value="RMNET">RMNET</option>
<option value="ECM (Recommended)">ECM (Recommended)</option>
<option value="MBIM">MBIM</option>
<option value="RNDIS">RNDIS</option>
</select>
</span>
<span class="icon is-small is-left">
@@ -269,22 +297,22 @@
</span>
</p>
<p class="help">
Selecting a mode will apply immediately.
Selecting a mode will apply immediately. Requires reboot.
</p>
</div>
</div>
<div class="cell">
<div class="cell advanced-settings">
<div class="field">
<label class="label">Onboard DNS Proxy Mode</label>
<p class="control has-icons-left">
<span class="select">
<select>
<select id="dns-proxy-mode">
<option selected>
Select Onboard DNS Proxy
</option>
<option>Enable</option>
<option>Disable</option>
<option value="Enabled">Enabled</option>
<option value="Disabled">Disabled</option>
</select>
</span>
<span class="icon is-small is-left">
@@ -300,7 +328,7 @@
</div>
</div>
<div class="cell">
<!-- <div class="cell">
<div class="fixed-grid has-2-cols">
<div class="grid is-gap-3">
<div class="cell">
@@ -356,19 +384,81 @@
</div>
</div>
</div>
</div> -->
<div class="cell">
<div class="fixed-grid has-2-cols">
<div class="grid is-gap-3">
<div class="cell">
<div class="field">
<label class="label">TTL State</label>
<div class="control has-icons-right">
<input
id="ttl-state"
class="input is-warning has-text-weight-bold"
placeholder="Disabled"
disabled
/>
<span class="icon is-small is-right">
<i
class="fas fa-exclamation-triangle has-text-warning"
></i>
</span>
</div>
</div>
</div>
<div class="cell">
<div class="field">
<label class="label">Current TTL Value</label>
<div class="control has-icons-right">
<input
id="ttl-current-value"
class="input is-warning has-text-weight-bold has-text-white"
placeholder="0"
disabled
/>
<span class="icon is-small is-right">
<i
class="fas fa-exclamation-triangle has-text-warning"
></i>
</span>
</div>
</div>
</div>
<div class="cell is-col-span-2">
<div class="field">
<label class="label">TTL Value to Set</label>
<div class="control has-icons-left">
<input
id="ttl-set-value"
class="input"
type="number"
placeholder="Custom TTL Value"
/>
<span class="icon is-small is-left">
<i class="fas fa-wifi"></i>
</span>
</div>
<p class="help is-success has-text-weight-semibold">
Set the TTL Value to 0 to disable.
</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card-footer">
<a
href="#"
id="ttl-submit"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Save
Apply TTL Settings
</a>
<a
href="#"
class="card-footer-item has-text-link has-text-weight-semibold has-text-white"
>
Reset
@@ -418,7 +508,7 @@
<div class="modal-card">
<section class="modal-card-body rounded-edge">
<p class="subtitle" id="modal-message">
Do you want to reboot the device?
Do not do any action while the modem is rebooting.
</p>
<div id="loading-content" style="display: none">
<div class="custom-loader"></div>

View File

@@ -0,0 +1,66 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define the lock file
LOCK_FILE="/tmp/home_data.lock"
# Acquire the lock (wait if needed)
exec 200>$LOCK_FILE
flock -x 200
# Temporary files for input/output and AT port
INPUT_FILE="/tmp/input_$$.txt"
OUTPUT_FILE="/tmp/output_$$.txt"
AT_PORT="/dev/smd11"
# Debug file path
DEBUG_FILE="/tmp/debug-json-result.txt"
# Function to escape JSON strings (handling quotes and newlines)
escape_json() {
# Escape newlines and double quotes
echo "$1" | sed ':a;N;$!ba;s/\n/\\n/g; s/"/\\"/g'
}
# Initialize JSON response array
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in 'AT+QMAP="MPDN_RULE"' 'AT+QMAP="DHCPV4DNS"' 'AT+QCFG="usbnet"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"
# Run the command using atinout
atinout "$INPUT_FILE" "$AT_PORT" "$OUTPUT_FILE"
# Read the output from the output file
OUTPUT=$(cat "$OUTPUT_FILE")
# Escape special characters for JSON (escape only output)
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
# Append the response as an object to the JSON response array
JSON_RESPONSE="${JSON_RESPONSE}{\"response\":\"$ESCAPED_OUTPUT\"},"
done
# Remove the trailing comma and close the JSON array
if [ "${JSON_RESPONSE: -1}" = "," ]; then
JSON_RESPONSE="${JSON_RESPONSE%,}]"
else
JSON_RESPONSE="${JSON_RESPONSE}]"
fi
# Write the JSON response to the debug file for troubleshooting
echo "$JSON_RESPONSE" > "$DEBUG_FILE"
# Return the output as a valid JSON response
echo "$JSON_RESPONSE"
# Clean up temporary files
rm "$INPUT_FILE" "$OUTPUT_FILE"
# Release the lock
flock -u 200

49
www/cgi-bin/fetch_macs.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Create a temporary file to store the processed data
temp_file=$(mktemp)
# Process ARP entries and store in temporary file
arp -a | while IFS= read -r line; do
if [ -n "$line" ]; then
# Extract hostname (or IP if hostname is "?"), IP, and MAC
hostname=$(echo "$line" | awk '{print $1}')
ip=$(echo "$line" | awk -F '[()]' '{print $2}')
mac=$(echo "$line" | awk '{print $4}')
# Skip entries without valid MAC addresses
if [ "$mac" = "<incomplete>" ]; then
continue
fi
# If hostname is "?", use the IP address instead
if [ "$hostname" = "?" ]; then
hostname="$ip"
fi
# Store each entry in the temp file
echo "$hostname:$ip:$mac" >> "$temp_file"
fi
done
# Initialize JSON array
echo -n "["
# Process the temporary file to create JSON
first=true
while IFS=: read -r hostname ip mac; do
if [ "$first" = true ]; then
first=false
else
echo -n ","
fi
echo -n "{\"hostname\":\"$hostname\",\"ip\":\"$ip\",\"mac\":\"$mac\"}"
done < "$temp_file"
# Close the JSON array
echo "]"
# Clean up
rm -f "$temp_file"

94
www/cgi-bin/ttl.sh Normal file
View File

@@ -0,0 +1,94 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
ttl_file="/etc/firewall.user.ttl"
lan_utils_script="/etc/data/lanUtils.sh"
setup_persistent_config() {
if [ ! -f "$lan_utils_script" ]; then
echo "{\"success\": false, \"error\": \"lanUtils.sh not found\"}"
return 1
fi
# Backup the original script if not already done
if [ ! -f "${lan_utils_script}.bak" ]; then
cp "$lan_utils_script" "${lan_utils_script}.bak"
fi
# Add the local ttl_firewall_file line if it's not already present
if ! grep -q "local ttl_firewall_file" "$lan_utils_script"; then
sed -i '/local tcpmss_firewall_filev6/a \ local ttl_firewall_file=/etc/firewall.user.ttl' "$lan_utils_script"
fi
# Add the condition to include the ttl_firewall_file if it's not already present
if ! grep -q "if \[ -f \"\$ttl_firewall_file\" \]; then" "$lan_utils_script"; then
sed -i '/if \[ -f "\$tcpmss_firewall_filev6" \]; then/i \ if [ -f "\$ttl_firewall_file" ]; then\n cat \$ttl_firewall_file >> \$firewall_file\n fi' "$lan_utils_script"
fi
}
clear_existing_rules() {
local current_ttl=$1
if [ -n "$current_ttl" ]; then
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set "$current_ttl" 2>/dev/null
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set "$current_ttl" 2>/dev/null
fi
}
case "$REQUEST_METHOD" in
GET)
# Ensure consistent JSON format for GET requests
if [ -s "$ttl_file" ]; then
ttl_value=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
# Ensure ttl_value is a number, default to 0 if not
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
ttl_value=0
fi
echo "{\"isEnabled\": true, \"currentValue\": $ttl_value}"
else
echo "{\"isEnabled\": false, \"currentValue\": 0}"
fi
;;
POST)
read -r post_data
ttl_value=$(echo "$post_data" | sed 's/ttl=//')
# Ensure ttl_file exists
touch "$ttl_file" 2>/dev/null
if [ ! -f "$ttl_file" ]; then
echo "{\"success\": false, \"error\": \"Cannot create TTL file\"}"
exit 1
fi
# Setup persistent configuration
setup_persistent_config
# Get current TTL value for cleanup
current_ttl=$(grep 'iptables -t mangle -A POSTROUTING' "$ttl_file" | awk '{for(i=1;i<=NF;i++){if($i=="--ttl-set"){print $(i+1)}}}')
if ! [[ "$ttl_value" =~ ^[0-9]+$ ]]; then
echo "{\"success\": false, \"error\": \"Invalid TTL value\"}"
elif [ "$ttl_value" = "0" ]; then
clear_existing_rules "$current_ttl"
> "$ttl_file"
echo "{\"success\": true}"
else
# Clear existing rules
clear_existing_rules "$current_ttl"
# Set new rules
echo "iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set $ttl_value" > "$ttl_file"
echo "ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set $ttl_value" >> "$ttl_file"
# Apply the rules
iptables -t mangle -A POSTROUTING -o rmnet+ -j TTL --ttl-set "$ttl_value"
ip6tables -t mangle -A POSTROUTING -o rmnet+ -j HL --hl-set "$ttl_value"
echo "{\"success\": true}"
fi
;;
*)
echo "{\"success\": false, \"error\": \"Invalid request method\"}"
;;
esac

View File

@@ -0,0 +1,461 @@
async function fetchCurrentSettings() {
try {
const response = await fetch("/cgi-bin/advanced_settings.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log("Current settings:", data);
return data;
} catch (error) {
console.error("Error fetching current settings:", error);
return null;
}
}
async function fetchConnectedDevices() {
try {
const response = await fetch("/cgi-bin/fetch_macs.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log("Connected devices:", data);
return data;
} catch (error) {
console.error("Error fetching connected devices:", error);
return null;
}
}
function populateConnectedDevices(devices) {
const selectElement = document.getElementById("connected-devices");
if (!selectElement) {
console.error("Connected devices select element not found");
return;
}
// Clear existing options except the first one
while (selectElement.options.length > 1) {
selectElement.remove(1);
}
// Add new options
devices.forEach((device) => {
const option = document.createElement("option");
option.value = device.mac;
option.textContent = `${device.hostname} - ${device.mac}`;
selectElement.appendChild(option);
});
}
function updatePassthroughModeState(isEnabled) {
const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
if (!ipPassthroughSelect) return;
if (isEnabled) {
ipPassthroughSelect.removeAttribute("disabled");
ipPassthroughSelect.classList.remove("is-warning");
const helpText = ipPassthroughSelect.parentElement.querySelector(".help");
if (helpText) {
helpText.textContent = "Select a passthrough mode to apply.";
helpText.classList.remove("is-warning");
helpText.classList.add("is-info");
}
} else {
ipPassthroughSelect.setAttribute("disabled", "disabled");
ipPassthroughSelect.classList.add("is-warning");
ipPassthroughSelect.value = "Select IP Passthrough Mode";
const helpText = ipPassthroughSelect.parentElement.querySelector(".help");
if (helpText) {
helpText.textContent = "Please select a device first.";
helpText.classList.remove("is-info");
helpText.classList.add("is-warning");
}
}
}
function updateUIElements(data) {
// Get all required DOM elements
const elements = {
ipPassthrough: document.getElementById("ip-passthrough-mode"),
dnsProxy: document.getElementById("dns-proxy-mode"),
usbModem: document.getElementById("usb-modem-protocol"),
};
// Check if all elements exist
const missingElements = Object.entries(elements)
.filter(([key, element]) => !element)
.map(([key]) => key);
if (missingElements.length > 0) {
console.error("Missing DOM elements:", missingElements);
return false;
}
try {
// Initially disable IP Passthrough mode
updatePassthroughModeState(false);
// Passthrough Mode (will be disabled until device is selected)
const mpdnRuleLine = data[0].response.split("\n")[1];
if (mpdnRuleLine) {
const mpdnRule = mpdnRuleLine.split(":")[1].trim();
switch (mpdnRule) {
case '"MPDN_rule",0,0,0,0,0':
elements.ipPassthrough.value = "Disabled";
break;
case '"MPDN_rule",0,1,0,1,1':
elements.ipPassthrough.value = "ETH Only";
break;
case '"MPDN_rule",0,1,0,3,1':
elements.ipPassthrough.value = "USB Only";
break;
default:
elements.ipPassthrough.value = "Select IP Passthrough Mode";
break;
}
}
// DNS Proxy
const dnsProxyLine = data[1].response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.trim();
if (dnsProxyLine) {
elements.dnsProxy.value =
dnsProxyLine === '"disable"' ? "Disabled" : "Enabled";
} else {
elements.dnsProxy.value = "Select Onboard DNS Proxy";
}
// USB Modem Protocol
const usbModemProtocolLine = data[2].response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.trim();
switch (usbModemProtocolLine) {
case "0":
elements.usbModem.value = "RMNET";
break;
case "1":
elements.usbModem.value = "ECM (Recommended)";
break;
case "2":
elements.usbModem.value = "MBIM";
break;
case "3":
elements.usbModem.value = "RNDIS";
break;
default:
elements.usbModem.value = "Select USB Modem Protocol";
break;
}
return true;
} catch (error) {
console.error("Error updating UI elements:", error);
return false;
}
}
// Function to send an AT command based on the DNS proxy mode
async function sendDnsProxyCommand(command) {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log("DNS Proxy AT command executed:", data.output);
} catch (error) {
console.error("Error sending DNS Proxy AT command:", error);
}
}
// Function to handle DNS Proxy changes
function handleDnsProxyChange() {
const dnsProxySelect = document.getElementById("dns-proxy-mode");
const currentDnsProxyMode = dnsProxySelect.getAttribute("data-current-mode"); // Store current mode as a data attribute
dnsProxySelect.addEventListener("change", function (e) {
const selectedMode = e.target.value;
// Send AT command only if the selected mode differs from the current one
if (selectedMode !== currentDnsProxyMode) {
if (selectedMode === "Enabled") {
sendDnsProxyCommand('AT+QMAP="DHCPV4DNS","enable"');
} else if (selectedMode === "Disabled") {
sendDnsProxyCommand('AT+QMAP="DHCPV4DNS","disable"');
}
} else {
console.log("No changes made to DNS Proxy mode");
}
});
}
// Function to send an AT command based on the IP Passthrough mode
async function sendIpPassthroughCommand(command) {
if (command) {
showLoadingContent(); // Show loading content and hide the buttons
startCountdown(80); // Start the countdown for 5 seconds
}
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log("IP Passthrough AT command executed:", data.output);
} catch (error) {
console.error("Error sending IP Passthrough AT command:", error);
}
}
// Function to handle IP Passthrough mode changes
function handleIpPassthroughChange() {
// track if the device is selected by listening to the connected devices dropdown change event
const connectedDevicesSelect = document.getElementById("connected-devices");
if (connectedDevicesSelect) {
connectedDevicesSelect.addEventListener("change", function (e) {
const selectedMAC = e.target.value;
const selectedHostname = e.target.options[e.target.selectedIndex].text;
console.log("Selected device:", {
mac: selectedMAC,
hostname: selectedHostname,
});
// Enable/disable IP Passthrough mode based on selection
const isDeviceSelected = selectedMAC !== "Select Device MAC";
if (isDeviceSelected) {
updatePassthroughModeState(true);
} else {
updatePassthroughModeState(false);
}
});
}
const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
const currentIpPassthroughMode =
ipPassthroughSelect.getAttribute("data-current-mode"); // Store current mode as a data attribute
ipPassthroughSelect.addEventListener("change", function (e) {
const selectedMode = e.target.value;
const selectedDeviceMAC =
document.getElementById("connected-devices").value;
// Send AT command only if the selected mode differs from the current one
if (selectedMode !== currentIpPassthroughMode) {
let command;
switch (selectedMode) {
case "Disabled":
command = 'AT+QMPDN="MPDN_rule",0;+CFUN=1,1';
break;
case "ETH Only":
command = `AT+QMPDN="MPDN_rule",0,1,0,1,1,"${selectedDeviceMAC}"`;
break;
case "USB Only":
command = `AT+QMPDN="MPDN_rule",0,1,0,3,1,"${selectedDeviceMAC}"`;
break;
default:
console.error("Invalid IP Passthrough mode:", selectedMode);
return;
}
sendIpPassthroughCommand(command);
} else {
console.log("No changes made to IP Passthrough mode");
}
});
}
// Function to send an AT command based on the USB Modem Protocol
async function sendUsbModemProtocolCommand(command) {
try {
if (command) {
showLoadingContent(); // Show loading content and hide the buttons
startCountdown(80); // Start the countdown for 5 seconds
}
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log("USB Modem Protocol AT command executed:", data.output);
} catch (error) {
console.error("Error sending USB Modem Protocol AT command:", error);
}
}
// Function to handle USB Modem Protocol changes
function handleUsbModemProtocolChange() {
const usbModemSelect = document.getElementById("usb-modem-protocol");
const currentUsbModemProtocol = usbModemSelect.getAttribute(
"data-current-protocol"
); // Store current protocol as a data attribute
usbModemSelect.addEventListener("change", function (e) {
const selectedProtocol = e.target.value;
// Send AT command only if the selected protocol differs from the current one
if (selectedProtocol !== currentUsbModemProtocol) {
let command;
switch (selectedProtocol) {
case "RMNET":
command = 'AT+QCFG="usbnet",0;+CFUN=1,1';
break;
case "ECM (Recommended)":
command = 'AT+QCFG="usbnet",1;+CFUN=1,1';
break;
case "MBIM":
command = 'AT+QCFG="usbnet",2;+CFUN=1,1';
break;
case "RNDIS":
command = 'AT+QCFG="usbnet",3;+CFUN=1,1';
break;
default:
console.error("Invalid USB Modem Protocol:", selectedProtocol);
return;
}
sendUsbModemProtocolCommand(command);
} else {
console.log("No changes made to USB Modem Protocol");
}
});
}
// Function to show the modal
function showModal() {
const modal = document.getElementById("reboot-modal");
if (modal) {
modal.classList.add("is-active"); // Bulma modals require "is-active" to be shown
}
}
// Function to show loading content and show the modal
function showLoadingContent() {
document.getElementById("loading-content").style.display = "flex"; // Show the loading section
document.getElementById("modal-buttons").style.display = "none"; // Hide the buttons
// Activate the modal
showModal();
}
// Function to start the countdown
function startCountdown(duration) {
let countdownElement = document.getElementById("countdown");
let countdown = duration;
let interval = setInterval(function () {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(interval);
// Add any additional logic after countdown reaches 0 (like reloading or closing the modal)
location.reload(); // Reload the page
}
}, 1000);
}
// Function for initializing the page
function init() {
// Replace all i elements under the class advanced-settings with a spinner icon initially
const advancedSettingsIcons = document.querySelectorAll(
".advanced-settings i"
);
advancedSettingsIcons.forEach((icon) => {
icon.classList.add("fa-spinner", "fa-spin");
});
Promise.all([fetchCurrentSettings(), fetchConnectedDevices()])
.then(([settings, devices]) => {
if (settings) {
const updateSuccess = updateUIElements(settings);
if (!updateSuccess) {
console.error("Failed to update UI elements");
} else {
// Revert the spinner icons back to their original state
advancedSettingsIcons.forEach((icon) => {
icon.classList.remove("fa-spinner", "fa-spin");
});
handleDnsProxyChange(); // Add event listener for DNS Proxy changes
handleUsbModemProtocolChange(); // Add event listener for USB Modem Protocol changes
handleIpPassthroughChange(); // Add event listener for IP Passthrough changes
}
} else {
console.error("Failed to fetch current settings");
}
if (devices) {
populateConnectedDevices(devices);
} else {
console.error("Failed to fetch connected devices");
}
})
.catch((error) => {
console.error("Error during initialization:", error);
});
}
// Initialize event listeners when DOM is ready
// document.addEventListener("DOMContentLoaded", () => {
// // Initialize the page
// init();
// // Add event listener for usb modem protocol changes
// handleUsbModemProtocolChange();
// // Add event listener for connected devices dropdown
// const connectedDevicesSelect = document.getElementById("connected-devices");
// if (connectedDevicesSelect) {
// connectedDevicesSelect.addEventListener("change", function (e) {
// const selectedMAC = e.target.value;
// const selectedHostname = e.target.options[e.target.selectedIndex].text;
// console.log("Selected device:", {
// mac: selectedMAC,
// hostname: selectedHostname,
// });
// // Enable/disable IP Passthrough mode based on selection
// const isDeviceSelected = selectedMAC !== "Select Device MAC";
// updatePassthroughModeState(isDeviceSelected);
// });
// }
// // Add event listener for IP Passthrough mode changes
// const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
// if (ipPassthroughSelect) {
// ipPassthroughSelect.addEventListener("change", function (e) {
// const selectedMode = e.target.value;
// const connectedDevicesSelect =
// document.getElementById("connected-devices");
// const selectedMAC = connectedDevicesSelect
// ? connectedDevicesSelect.value
// : null;
// if (selectedMAC && selectedMAC !== "Select Device MAC") {
// console.log("Applying IP Passthrough mode:", {
// mode: selectedMode,
// deviceMAC: selectedMAC,
// });
// // Here you can add the API call to apply the passthrough mode
// } else {
// console.error("No device selected for IP Passthrough mode");
// e.target.value = "Select IP Passthrough Mode";
// }
// });
// }
// });
// Initialize event listeners when DOM is ready
document.addEventListener("DOMContentLoaded", () => {
// Initialize the page
init();
});

View File

@@ -0,0 +1,94 @@
// TTL Control functionality
const TTLControl = {
async getCurrentState() {
try {
const response = await fetch('/cgi-bin/ttl.sh');
const data = await response.json();
return {
isEnabled: data.isEnabled,
currentValue: data.currentValue || 0
};
} catch (error) {
console.error('Error fetching TTL state:', error);
return { isEnabled: false, currentValue: 0 };
}
},
async setTTLValue(value) {
try {
const response = await fetch('/cgi-bin/ttl.sh', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `ttl=${value}`
});
const result = await response.json();
return result.success;
} catch (error) {
console.error('Error setting TTL value:', error);
return false;
}
},
updateUI(isEnabled, value) {
const stateInput = document.getElementById('ttl-state');
const valueInput = document.getElementById('ttl-current-value');
const stateIcon = stateInput.nextElementSibling.querySelector('i');
const valueIcon = valueInput.nextElementSibling.querySelector('i');
// Update State UI
if (isEnabled) {
// Enabled state
stateInput.value = 'Enabled';
stateInput.classList.remove('has-text-warning', 'is-danger');
stateInput.classList.add('has-text-success', 'has-text-weight-bold');
stateIcon.classList.remove('fa-exclamation-triangle', 'has-text-warning');
stateIcon.classList.add('fa-check', 'has-text-success');
} else {
// Disabled state
stateInput.value = 'Disabled';
stateInput.classList.remove('has-text-success', 'is-danger');
stateInput.classList.add('has-text-warning', 'has-text-weight-bold');
stateIcon.classList.remove('fa-check', 'has-text-success');
stateIcon.classList.add('fa-exclamation-triangle', 'has-text-warning');
}
// Update Value UI
valueInput.value = value.toString();
valueInput.classList.add('has-text-weight-bold', 'has-text-white');
if (isEnabled) {
valueIcon.classList.remove('fa-exclamation-triangle', 'has-text-warning');
valueIcon.classList.add('fa-check', 'has-text-success');
} else {
valueIcon.classList.remove('fa-check', 'has-text-success');
valueIcon.classList.add('fa-exclamation-triangle', 'has-text-warning');
}
}
};
// Event Listeners
document.addEventListener('DOMContentLoaded', async function() {
// Initial state fetch
const { isEnabled, currentValue } = await TTLControl.getCurrentState();
TTLControl.updateUI(isEnabled, currentValue);
// Submit button event listener
document.getElementById('ttl-submit').addEventListener('click', async function() {
const newValue = document.getElementById('ttl-set-value').value;
const numValue = parseInt(newValue);
if (isNaN(numValue) || numValue < 0) {
alert('Please enter a valid TTL value (0 or positive number)');
return;
}
const success = await TTLControl.setTTLValue(numValue);
if (success) {
TTLControl.updateUI(numValue !== 0, numValue);
alert('TTL settings updated successfully');
} else {
alert('Failed to update TTL settings');
}
});
});