Initial Commit
Start new branch for development on new 64bit x75 platfom.
This commit is contained in:
22
Belowx65Toolkit/LICENSE
Normal file
22
Belowx65Toolkit/LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
MIT License with Additional Stipulations
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
1. A clear and visible attribution to the original author (you) must be provided in an obvious place in any product, documentation, or interface where the software is utilized. This attribution should include your name and a reference to the original source repository.
|
||||
|
||||
2. The Software, or any modified version of it, must not be sold or charged for. However, selling physical products that include the Software is permitted, provided that a clear and visible attribution to the original author (you) is included in an obvious place in the product or accompanying documentation.
|
||||
|
||||
3. Any modifications made to the Software must be made available upon request by any party. This includes providing access to the modified source code, along with any accompanying documentation necessary for understanding the modifications.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
158
Belowx65Toolkit/README.md
Normal file
158
Belowx65Toolkit/README.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# RGMII Toolkit
|
||||
Software deployment Toolkit for Quectel RM5xxx series 5G modems utilizing an m.2 to RJ45 adapter (RGMII)
|
||||
|
||||
Current Branch: **Development**
|
||||
|
||||
Please PR to this branch instead of main :)
|
||||
|
||||
Fork development, and PR development to development :)
|
||||
|
||||
|
||||
#### [JUMP TO HOW TO USE](#how-to-use)
|
||||
**Currently:** This will allow you to install or if already installed, update, remove, or modify:
|
||||
- Simple Admin: A simple web interface for managing your Quectel m.2 modem through it's gateway address
|
||||
- It will install socat-at-bridge: sets up ttyOUT and ttyOUT2 for AT commands. You'll be able to use the `atcmd` command as well for an interactive at command session from adb, ssh, or ttyd
|
||||
- It will install simplefirewall: A simple firewall that blocks definable incoming ports and a TTL mangle option/modifier. As of now only the TTL is controllable through Simple Admin. You can edit port block options and TTL from the 3rd option in the toolkit
|
||||
- Tailscale: A magic VPN for accessing Simple Admin, SSH, and ttyd on the go. The Toolkit installs the Tailscale client directly to the modem and allows you to login and configure other settings. Head over to tailscale.com to sign up for a free account and learn more.
|
||||
- Schedule a Daily Reboot at a specified time
|
||||
- A fix for certain modems that don't start in CFUN=1 mode
|
||||
- Entware/OPKG: A package installer/manager/repo
|
||||
- Run `opkg help` to see how to use it
|
||||
- These packages are installable: https://bin.entware.net/armv7sf-k3.2/Packages.html
|
||||
- TTYd: A shell session right from your browser
|
||||
- Currently this uses port 443 but SSL/TLS is not in use (http only for now)
|
||||
- Entware/OPKG is required so it will install it if it isn't installed
|
||||
- This will replace the stock Quectel login and passwd binaries with ones from entware
|
||||
|
||||
|
||||
|
||||
**My goal** is for this to also include any new useful scripts or software for this modem and others that support RGMII mode.
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# Devleopment Branch: the below commands will download the beta/work in progress toolkit
|
||||
|
||||
## How to Use
|
||||
**To run the Toolkit:**
|
||||
- Open ADB & Fastboot++ covered in [Using ADB](https://github.com/iamromulan/quectel-rgmii-configuration-notes?tab=readme-ov-file#unlocking-and-using-adb) or just use adb
|
||||
- Make sure your modem is connected by USB to your computer
|
||||
- Run `adb devices` to make sure your modem is detected by adb
|
||||
- Run `adb shell ping 8.8.8.8` to make sure the shell can access the internet. If you get an error, make sure the modem is connected to a cellular network and make sure `AT+QMAPWAC=1` as covered in the troubleshooting section: [I Can't get internet access from the Ethernet port (Common)](https://github.com/iamromulan/quectel-rgmii-configuration-notes/tree/main?tab=readme-ov-file#i-cant-get-internet-access-from-the-ethernet-port-common)
|
||||
- If you don't get an error you should be getting replies back endlessly, press `CTRL-C` to stop it.
|
||||
- Simply Copy/Paste this into your Command Prompt/Shell
|
||||
```bash
|
||||
adb shell "cd /tmp && wget -O RMxxx_rgmii_toolkit.sh https://raw.githubusercontent.com/iamromulan/quectel-rgmii-toolkit/development/RMxxx_rgmii_toolkit.sh && chmod +x RMxxx_rgmii_toolkit.sh && ./RMxxx_rgmii_toolkit.sh" && cd /
|
||||
```
|
||||
|
||||
**Or, if you want to stay in the modems shell when you are done**
|
||||
|
||||
```
|
||||
adb shell
|
||||
```
|
||||
Then run
|
||||
```
|
||||
cd /tmp && wget -O RMxxx_rgmii_toolkit.sh https://raw.githubusercontent.com/iamromulan/quectel-rgmii-toolkit/development/RMxxx_rgmii_toolkit.sh && chmod +x RMxxx_rgmii_toolkit.sh && ./RMxxx_rgmii_toolkit.sh && cd /
|
||||
```
|
||||
**You should see:**
|
||||

|
||||
|
||||
## Tailscale Installation and Config
|
||||
|
||||
> :warning: Your modem must already be connected to the internet for this to install
|
||||
### Installation:
|
||||
Open up the toolkit main menu and **press 4** to enter the Tailscale menu
|
||||
|
||||

|
||||
|
||||
**Press 1, wait for it to install. This is a very large file for the system so give it some time.**
|
||||
|
||||
**Once done and it says Tailscale installed successfully press 2/enter to configure it.**
|
||||
|
||||

|
||||
|
||||
If you want to, enable the Tailscale Web UI on port 8088 for configuration from the browser later by **pressing 1/enter**.
|
||||
|
||||
To do it in the toolkit:
|
||||
First time connecting you'll be given a link to login with
|
||||
- Press 3 to just connect only.
|
||||
- Press 4 to connect and enable SSH access (remote command line) over tailscale.
|
||||
- Press 5 to reconnect with SSH off while connected with SSH on
|
||||
- Press 6 to disconnect
|
||||
- Press 7 to Logout
|
||||
|
||||
That's it! From another device running tailscale you should be able to access your modem through the IP assigned to it by your tailnet. To access SSH from another device on the tailnet, open a terminal/command prompt and type
|
||||
|
||||
tailscale ssh root@(IP or Hostname)
|
||||
IP or Hostname being the IP or hostname assigned to it in your tailnet
|
||||
|
||||
- Note that your SSH client must be able to give you a link to sign in with upon connecting. That's how the session is authorized. Works fine in Windows CMD or on Android use JuiceSSH.
|
||||
## Advanced/Beta
|
||||
|
||||
### Entware/OPKG installation
|
||||
|
||||
|
||||
It isn't perfect yet so it goes here under Advanced/Beta for now.
|
||||
Here's what you gotta know about going into it:
|
||||
|
||||
- After installing, the `opkg` command will work
|
||||
- You can run `opkg list` to see a list of installable packages, or head over to https://bin.entware.net/armv7sf-k3.2/Packages.html
|
||||
- Everything opkg does is installed to /opt
|
||||
- `/opt` is actually located at `/usrdata/opt` to save space but is
|
||||
mounted at `/opt`
|
||||
- Anything `opkg` installs will not be available in the system path by
|
||||
default but you can get around this either:
|
||||
|
||||
#### Temporarily:
|
||||
Run this at the start of each adb shell or SSH shell session
|
||||
|
||||
export PATH=/opt/bin:/opt/sbin:$PATH
|
||||
|
||||
#### Permanently:
|
||||
Symbolic linking each binary installed by the package to `/bin` and `/sbin` from `/opt/bin` and `/opt/sbin`
|
||||
For example, if you were to install zerotier:
|
||||
|
||||
opkg install zerotier
|
||||
ln -sf /opt/bin/zerotier-one /bin
|
||||
ln -sf /opt/bin/zerotier-cli /bin
|
||||
ln -sf /opt/bin/zerotier-idtool /bin
|
||||
|
||||
Now you can run those 3 binaries from the shell anytime since they are linked in a place already part of the system path.
|
||||
|
||||
I plan to create a watchdog service for /opt/bin and /opt/sbin that will automaticly link new packages to /bin or /sbin later on in order to combat this.
|
||||
|
||||
### TTYd installation
|
||||
|
||||
It isn't perfect yet so it goes here under Advanced/Beta for now.
|
||||
Here's what you gotta know about going into it:
|
||||
|
||||
- This listens on port 443 for http requests (no SSL/TLS yet)
|
||||
- This will automaticly install entware and patch the login and passwd binaries with ones from entware
|
||||
- It will ask you to set a password for the `root` user account
|
||||
- TTYd doesn't seem to be too mobile friendly for now but I optimized it the best i could for now so it is at least usable through a smartphone browser. Hopefully the startup script can be improved even more later.
|
||||
|
||||
## Acknowledgements
|
||||
### GitHub Users/Individuals:
|
||||
Thank You to:
|
||||
|
||||
[Nate Carlson](https://github.com/natecarlson) for the Original Telnet Deamon/socat bridge usage and the Original RGMII Notes
|
||||
|
||||
[aesthernr](https://github.com/aesthernr) for creating the Original Simple Admin
|
||||
|
||||
[rbflurry](https://github.com/rbflurry/) for inital Simple Admin fixes
|
||||
|
||||
[dr-dolomite](https://github.com/dr-dolomite) for some major stat page improvements and this repos first approved external PR!
|
||||
|
||||
[tarunVreddy](https://github.com/tarunVreddy) for helping with the SA band aggregation parse
|
||||
|
||||
### Existing projects:
|
||||
Simpleadmin heavily uses the AT Command Parsing Scripts (Basically a copy with new changes and tweaks) of Dairyman's Rooter Source https://github.com/ofmodemsandmen/ROOterSource2203
|
||||
|
||||
Tailscale was obtained through Tailscale's static build page. Since these modems have a 32-bit ARM processor on-board I used the arm package. https://pkgs.tailscale.com/stable/#static
|
||||
|
||||
Entware/opkg was obtained through [Entware's wiki](https://github.com/Entware/Entware/wiki/Alternative-install-vs-standard) and the installer heavily modified by [iamromulan](https://github.com/iamromulan) for use with Quectel modems
|
||||
|
||||
TTYd was obtained from the [TTYd Project](https://github.com/tsl0922/ttyd)
|
||||
950
Belowx65Toolkit/RMxxx_rgmii_toolkit.sh
Normal file
950
Belowx65Toolkit/RMxxx_rgmii_toolkit.sh
Normal file
@@ -0,0 +1,950 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Define toolkit paths
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
GITMAINTREE="main"
|
||||
GITDEVTREE="development"
|
||||
TMP_DIR="/tmp"
|
||||
USRDATA_DIR="/usrdata"
|
||||
SOCAT_AT_DIR="/usrdata/socat-at-bridge"
|
||||
SOCAT_AT_SYSD_DIR="/usrdata/socat-at-bridge/systemd_units"
|
||||
SIMPLE_ADMIN_DIR="/usrdata/simpleadmin"
|
||||
SIMPLE_FIREWALL_DIR="/usrdata/simplefirewall"
|
||||
SIMPLE_FIREWALL_SCRIPT="$SIMPLE_FIREWALL_DIR/simplefirewall.sh"
|
||||
SIMPLE_FIREWALL_SYSTEMD_DIR="$SIMPLE_FIREWALL_DIR/systemd"
|
||||
TAILSCALE_DIR="/usrdata/tailscale"
|
||||
TAILSCALE_SYSD_DIR="/usrdata/tailscale/systemd"
|
||||
# AT Command Script Variables and Functions
|
||||
DEVICE_FILE="/dev/smd7"
|
||||
TIMEOUT=4 # Set a timeout for the response
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
# Basic AT commands without socat bridge for fast responce commands only
|
||||
start_listening() {
|
||||
cat "$DEVICE_FILE" > /tmp/device_readout &
|
||||
CAT_PID=$!
|
||||
}
|
||||
|
||||
send_at_command() {
|
||||
echo -e "\e[1;31mThis only works for basic quick responding commands!\e[0m" # Red
|
||||
echo -e "\e[1;36mType 'install' to simply type atcmd in shell from now on\e[0m"
|
||||
echo -e "\e[1;36mThe installed version is much better than this portable version\e[0m"
|
||||
echo -e "\e[1;32mEnter AT command (or type 'exit' to quit): \e[0m"
|
||||
read at_command
|
||||
if [ "$at_command" = "exit" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$at_command" = "install" ]; then
|
||||
install_update_at_socat
|
||||
echo -e "\e[1;32mInstalled. Type atcmd from adb shell or ssh to start an AT Command session\e[0m"
|
||||
return 1
|
||||
fi
|
||||
echo -e "${at_command}\r" > "$DEVICE_FILE"
|
||||
}
|
||||
|
||||
wait_for_response() {
|
||||
local start_time=$(date +%s)
|
||||
local current_time
|
||||
local elapsed_time
|
||||
|
||||
echo -e "\e[1;32mCommand sent, waiting for response...\e[0m"
|
||||
while true; do
|
||||
if grep -qe "OK" -e "ERROR" /tmp/device_readout; then
|
||||
echo -e "\e[1;32mResponse received:\e[0m"
|
||||
cat /tmp/device_readout
|
||||
return 0
|
||||
fi
|
||||
current_time=$(date +%s)
|
||||
elapsed_time=$((current_time - start_time))
|
||||
if [ "$elapsed_time" -ge "$TIMEOUT" ]; then
|
||||
echo -e "\e[1;31mError: Response timed out.\e[0m" # Red
|
||||
echo -e "\e[1;32mIf the responce takes longer than a second or 2 to respond this will not work\e[0m" # Green
|
||||
echo -e "\e[1;36mType install to install the better version of this that will work.\e[0m" # Cyan
|
||||
return 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
kill "$CAT_PID"
|
||||
wait "$CAT_PID" 2>/dev/null
|
||||
rm -f /tmp/device_readout
|
||||
}
|
||||
|
||||
send_at_commands() {
|
||||
if [ -c "$DEVICE_FILE" ]; then
|
||||
while true; do
|
||||
start_listening
|
||||
send_at_command
|
||||
if [ $? -eq 1 ]; then
|
||||
cleanup
|
||||
break
|
||||
fi
|
||||
wait_for_response
|
||||
cleanup
|
||||
done
|
||||
else
|
||||
echo -e "\e[1;31mError: Device $DEVICE_FILE does not exist!\e[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for existing Entware/opkg installation, install if not installed
|
||||
ensure_entware_installed() {
|
||||
remount_rw
|
||||
if [ ! -f "/opt/bin/opkg" ]; then
|
||||
echo -e "\e[1;32mInstalling Entware/OPKG\e[0m"
|
||||
cd /tmp && wget -O installentware.sh "https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/installentware.sh" && chmod +x installentware.sh && ./installentware.sh
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo -e "\e[1;31mEntware/OPKG installation failed. Please check your internet connection or the repository URL.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
cd /
|
||||
else
|
||||
echo -e "\e[1;32mEntware/OPKG is already installed.\e[0m"
|
||||
if [ "$(readlink /bin/login)" != "/opt/bin/login" ]; then
|
||||
opkg update && opkg install shadow-login shadow-passwd shadow-useradd
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo -e "\e[1;31mPackage installation failed. Please check your internet connection and try again.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Replace the login and passwd binaries and set home for root to a writable directory
|
||||
rm /opt/etc/shadow
|
||||
rm /opt/etc/passwd
|
||||
cp /etc/shadow /opt/etc/
|
||||
cp /etc/passwd /opt/etc
|
||||
mkdir -p /usrdata/root/bin
|
||||
touch /usrdata/root/.profile
|
||||
echo "# Set PATH for all shells" > /usrdata/root/.profile
|
||||
echo "export PATH=/bin:/usr/sbin:/usr/bin:/sbin:/opt/sbin:/opt/bin:/usrdata/root/bin" >> /usrdata/root/.profile
|
||||
chmod +x /usrdata/root/.profile
|
||||
sed -i '1s|/home/root:/bin/sh|/usrdata/root:/bin/bash|' /opt/etc/passwd
|
||||
rm /bin/login /usr/bin/passwd
|
||||
ln -sf /opt/bin/login /bin
|
||||
ln -sf /opt/bin/passwd /usr/bin/
|
||||
ln -sf /opt/bin/useradd /usr/bin/
|
||||
echo -e "\e[1;31mPlease set the root password.\e[0m"
|
||||
/opt/bin/passwd
|
||||
|
||||
# Install basic and useful utilities
|
||||
opkg install mc htop dfc lsof
|
||||
ln -sf /opt/bin/mc /bin
|
||||
ln -sf /opt/bin/htop /bin
|
||||
ln -sf /opt/bin/dfc /bin
|
||||
ln -sf /opt/bin/lsof /bin
|
||||
fi
|
||||
|
||||
if [ ! -f "/usrdata/root/.profile" ]; then
|
||||
opkg update && opkg install shadow-useradd
|
||||
mkdir -p /usrdata/root/bin
|
||||
touch /usrdata/root/.profile
|
||||
echo "# Set PATH for all shells" > /usrdata/root/.profile
|
||||
echo "export PATH=/bin:/usr/sbin:/usr/bin:/sbin:/opt/sbin:/opt/bin:/usrdata/root/bin" >> /usrdata/root/.profile
|
||||
chmod +x /usrdata/root/.profile
|
||||
sed -i '1s|/home/root:/bin/sh|/usrdata/root:/bin/bash|' /opt/etc/passwd
|
||||
fi
|
||||
fi
|
||||
if [ ! -f "/opt/sbin/useradd" ]; then
|
||||
echo "useradd does not exist. Installing shadow-useradd..."
|
||||
opkg install shadow-useradd
|
||||
else
|
||||
echo "useradd already exists. Continuing..."
|
||||
fi
|
||||
|
||||
if [ ! -f "/usr/bin/curl" ] && [ ! -f "/opt/bin/curl" ]; then
|
||||
echo "curl does not exist. Installing curl..."
|
||||
opkg update && opkg install curl
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo -e "\e[1;31mFailed to install curl. Please check your internet connection and try again.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "curl already exists. Continuing..."
|
||||
fi
|
||||
}
|
||||
|
||||
#Uninstall Entware if the Users chooses
|
||||
uninstall_entware() {
|
||||
echo -e '\033[31mInfo: Starting Entware/OPKG uninstallation...\033[0m'
|
||||
|
||||
# Stop services
|
||||
systemctl stop rc.unslung.service
|
||||
/opt/etc/init.d/rc.unslung stop
|
||||
rm /lib/systemd/system/multi-user.target.wants/rc.unslung.service
|
||||
rm /lib/systemd/system/rc.unslung.service
|
||||
|
||||
systemctl stop opt.mount
|
||||
rm /lib/systemd/system/multi-user.target.wants/start-opt-mount.service
|
||||
rm /lib/systemd/system/opt.mount
|
||||
rm /lib/systemd/system/start-opt-mount.service
|
||||
|
||||
# Unmount /opt if mounted
|
||||
mountpoint -q /opt && umount /opt
|
||||
|
||||
# Remove Entware installation directory
|
||||
rm -rf /usrdata/opt
|
||||
rm -rf /opt
|
||||
|
||||
# Reload systemctl daemon
|
||||
systemctl daemon-reload
|
||||
|
||||
# Optionally, clean up any modifications to /etc/profile or other system files
|
||||
# Restore original link to login binary compiled by Quectel
|
||||
rm /bin/login
|
||||
ln /bin/login.shadow /bin/login
|
||||
|
||||
echo -e '\033[32mInfo: Entware/OPKG has been uninstalled successfully.\033[0m'
|
||||
}
|
||||
|
||||
# function to configure the fetures of simplefirewall
|
||||
configure_simple_firewall() {
|
||||
if [ ! -f "$SIMPLE_FIREWALL_SCRIPT" ]; then
|
||||
echo -e "\033[0;31mSimplefirewall is not installed, would you like to install it?\033[0m"
|
||||
echo -e "\033[0;32m1) Yes\033[0m"
|
||||
echo -e "\033[0;31m2) No\033[0m"
|
||||
read -p "Enter your choice (1-2): " install_choice
|
||||
|
||||
case $install_choice in
|
||||
1)
|
||||
install_simple_firewall
|
||||
;;
|
||||
2)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
echo -e "\033[0;31mInvalid choice. Please select either 1 or 2.\033[0m"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
echo -e "\e[1;32mConfigure Simple Firewall:\e[0m"
|
||||
echo -e "\e[38;5;208m1) Configure incoming port block\e[0m"
|
||||
echo -e "\e[38;5;27m2) Configure TTL\e[0m"
|
||||
read -p "Enter your choice (1-2): " menu_choice
|
||||
|
||||
case $menu_choice in
|
||||
1)
|
||||
# Original ports configuration code with exit option
|
||||
current_ports_line=$(grep '^PORTS=' "$SIMPLE_FIREWALL_SCRIPT")
|
||||
ports=$(echo "$current_ports_line" | cut -d'=' -f2 | tr -d '()' | tr ' ' '\n' | grep -o '[0-9]\+')
|
||||
echo -e "\e[1;32mCurrent configured ports:\e[0m"
|
||||
echo "$ports" | awk '{print NR") "$0}'
|
||||
|
||||
while true; do
|
||||
echo -e "\e[1;32mEnter a port number to add/remove, or type 'done' or 'exit' to finish:\e[0m"
|
||||
read port
|
||||
if [ "$port" = "done" ] || [ "$port" = "exit" ]; then
|
||||
if [ "$port" = "exit" ]; then
|
||||
echo -e "\e[1;31mExiting without making changes...\e[0m"
|
||||
return
|
||||
fi
|
||||
break
|
||||
elif ! echo "$port" | grep -qE '^[0-9]+$'; then
|
||||
echo -e "\e[1;31mInvalid input: Please enter a numeric value.\e[0m"
|
||||
elif echo "$ports" | grep -q "^$port\$"; then
|
||||
ports=$(echo "$ports" | grep -v "^$port\$")
|
||||
echo -e "\e[1;32mPort $port removed.\e[0m"
|
||||
else
|
||||
ports=$(echo "$ports"; echo "$port" | grep -o '[0-9]\+')
|
||||
echo -e "\e[1;32mPort $port added.\e[0m"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$port" != "exit" ]; then
|
||||
new_ports_line="PORTS=($(echo "$ports" | tr '\n' ' '))"
|
||||
sed -i "s/$current_ports_line/$new_ports_line/" "$SIMPLE_FIREWALL_SCRIPT"
|
||||
fi
|
||||
;;
|
||||
2)
|
||||
# TTL configuration code
|
||||
ttl_value=$(cat /usrdata/simplefirewall/ttlvalue)
|
||||
if [ "$ttl_value" -eq 0 ]; then
|
||||
echo -e "\e[1;31mTTL is not set.\e[0m"
|
||||
else
|
||||
echo -e "\e[1;32mTTL value is set to $ttl_value.\e[0m"
|
||||
fi
|
||||
|
||||
echo -e "\e[1;31mType 'exit' to cancel.\e[0m"
|
||||
read -p "What do you want the TTL value to be: " new_ttl_value
|
||||
if [ "$new_ttl_value" = "exit" ]; then
|
||||
echo -e "\e[1;31mExiting TTL configuration...\e[0m"
|
||||
return
|
||||
elif ! echo "$new_ttl_value" | grep -qE '^[0-9]+$'; then
|
||||
echo -e "\e[1;31mInvalid input: Please enter a numeric value.\e[0m"
|
||||
return
|
||||
else
|
||||
/usrdata/simplefirewall/ttl-override stop
|
||||
echo "$new_ttl_value" > /usrdata/simplefirewall/ttlvalue
|
||||
/usrdata/simplefirewall/ttl-override start
|
||||
echo -e "\033[0;32mTTL value updated to $new_ttl_value.\033[0m"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\e[1;31mInvalid choice. Please select either 1 or 2.\e[0m"
|
||||
;;
|
||||
esac
|
||||
|
||||
systemctl restart simplefirewall
|
||||
echo -e "\e[1;32mFirewall configuration updated.\e[0m"
|
||||
}
|
||||
|
||||
set_simpleadmin_passwd(){
|
||||
ensure_entware_installed
|
||||
opkg update
|
||||
opkg install libaprutil
|
||||
wget -O /usrdata/root/bin/htpasswd https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/htpasswd && chmod +x /usrdata/root/bin/htpasswd
|
||||
wget -O /usrdata/root/bin/simplepasswd https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/simplepasswd && chmod +x /usrdata/root/bin/simplepasswd
|
||||
echo -e "\e[1;32mTo change your simpleadmin (admin) password in the future...\e[0m"
|
||||
echo -e "\e[1;32mIn the console type simplepasswd and press enter\e[0m"
|
||||
/usrdata/root/bin/simplepasswd
|
||||
|
||||
}
|
||||
|
||||
set_root_passwd() {
|
||||
echo -e "\e[1;31mPlease set the root/console password.\e[0m"
|
||||
/opt/bin/passwd
|
||||
}
|
||||
|
||||
# Function to install/update Simple Admin
|
||||
install_simple_admin() {
|
||||
while true; do
|
||||
echo -e "\e[1;32mWhat version of Simple Admin do you want to install? This will start a webserver on port 80/443 on test build\e[0m"
|
||||
echo -e "\e[1;32m1) Stable current version, (Main Branch)\e[0m"
|
||||
echo -e "\e[1;31m2) Install Test Build (Development Branch)\e[0m"
|
||||
echo -e "\e[0;33m3) Return to Main Menu\e[0m"
|
||||
echo -e "\e[1;32mSelect your choice: \e[0m"
|
||||
read choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
echo -e "\e[1;32mYou are using the development toolkit; Use the one from main if you want the stable version right now\e[0m"
|
||||
break
|
||||
;;
|
||||
2)
|
||||
ensure_entware_installed
|
||||
echo -e "\e[1;31m2) Installing simpleadmin from the development test branch\e[0m"
|
||||
mkdir /usrdata/simpleupdates > /dev/null 2>&1
|
||||
mkdir /usrdata/simpleupdates/scripts > /dev/null 2>&1
|
||||
wget -O /usrdata/simpleupdates/scripts/update_socat-at-bridge.sh https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleupdates/scripts/update_socat-at-bridge.sh && chmod +x /usrdata/simpleupdates/scripts/update_socat-at-bridge.sh
|
||||
echo -e "\e[1;32mInstalling/updating dependency: socat-at-bridge\e[0m"
|
||||
echo -e "\e[1;32mPlease Wait....\e[0m"
|
||||
/usrdata/simpleupdates/scripts/update_socat-at-bridge.sh
|
||||
echo -e "\e[1;32m Dependency: socat-at-bridge has been updated/installed.\e[0m"
|
||||
sleep 1
|
||||
wget -O /usrdata/simpleupdates/scripts/update_simplefirewall.sh https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleupdates/scripts/update_simplefirewall.sh && chmod +x /usrdata/simpleupdates/scripts/update_simplefirewall.sh
|
||||
echo -e "\e[1;32mInstalling/updating dependency: simplefirewall\e[0m"
|
||||
echo -e "\e[1;32mPlease Wait....\e[0m"
|
||||
/usrdata/simpleupdates/scripts/update_simplefirewall.sh
|
||||
echo -e "\e[1;32m Dependency: simplefirewall has been updated/installed.\e[0m"
|
||||
sleep 1
|
||||
set_simpleadmin_passwd
|
||||
wget -O /usrdata/simpleupdates/scripts/update_simpleadmin.sh https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleupdates/scripts/update_simpleadmin.sh && chmod +x /usrdata/simpleupdates/scripts/update_simpleadmin.sh
|
||||
echo -e "\e[1;32mInstalling/updating: Simpleadmin content\e[0m"
|
||||
echo -e "\e[1;32mPlease Wait....\e[0m"
|
||||
/usrdata/simpleupdates/scripts/update_simpleadmin.sh
|
||||
echo -e "\e[1;32mSimpleadmin content has been updated/installed.\e[0m"
|
||||
sleep 1
|
||||
break
|
||||
;;
|
||||
3)
|
||||
echo "Returning to main menu..."
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "Invalid choice. Please try again."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Function to Uninstall Simpleadmin and dependencies
|
||||
uninstall_simpleadmin_components() {
|
||||
echo -e "\e[1;32mStarting the uninstallation process for Simpleadmin components.\e[0m"
|
||||
echo -e "\e[1;32mNote: Uninstalling certain components may affect the functionality of others.\e[0m"
|
||||
remount_rw
|
||||
|
||||
# Uninstall Simple Firewall
|
||||
echo -e "\e[1;32mDo you want to uninstall Simplefirewall?\e[0m"
|
||||
echo -e "\e[1;31mIf you do, the TTL part of simpleadmin will no longer work.\e[0m"
|
||||
echo -e "\e[1;32m1) Yes\e[0m"
|
||||
echo -e "\e[1;31m2) No\e[0m"
|
||||
read -p "Enter your choice (1 or 2): " choice_simplefirewall
|
||||
if [ "$choice_simplefirewall" -eq 1 ]; then
|
||||
echo "Uninstalling Simplefirewall..."
|
||||
systemctl stop simplefirewall
|
||||
systemctl stop ttl-override
|
||||
rm -f /lib/systemd/system/simplefirewall.service
|
||||
rm -f /lib/systemd/system/ttl-override.service
|
||||
systemctl daemon-reload
|
||||
rm -rf "$SIMPLE_FIREWALL_DIR"
|
||||
echo "Simplefirewall uninstalled."
|
||||
fi
|
||||
|
||||
# Uninstall socat-at-bridge
|
||||
echo -e "\e[1;32mDo you want to uninstall socat-at-bridge?\e[0m"
|
||||
echo -e "\e[1;31mIf you do, AT commands and the stat page will no longer work. atcmd won't either.\e[0m"
|
||||
echo -e "\e[1;32m1) Yes\e[0m"
|
||||
echo -e "\e[1;31m2) No\e[0m"
|
||||
read -p "Enter your choice (1 or 2): " choice_socat_at_bridge
|
||||
if [ "$choice_socat_at_bridge" -eq 1 ]; then
|
||||
echo -e "\033[0;32mRemoving installed AT Socat Bridge services...\033[0m"
|
||||
systemctl stop at-telnet-daemon > /dev/null 2>&1
|
||||
systemctl disable at-telnet-daemon > /dev/null 2>&1
|
||||
systemctl stop socat-smd11 > /dev/null 2>&1
|
||||
systemctl stop socat-smd11-to-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd11-from-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd7 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-to-ttyIN2 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-to-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-from-ttyIN2 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-from-ttyIN > /dev/null 2>&1
|
||||
rm /lib/systemd/system/at-telnet-daemon.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11-to-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11-from-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-to-ttyIN2.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-to-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-from-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-from-ttyIN2.service > /dev/null 2>&1
|
||||
systemctl daemon-reload > /dev/null 2>&1
|
||||
rm -rf "$SOCAT_AT_DIR" > /dev/null 2>&1
|
||||
rm -rf "$SOCAT_AT_DIR" > /dev/null 2>&1
|
||||
rm -rf "/usrdata/micropython" > /dev/null 2>&1
|
||||
rm -rf "/usrdata/at-telnet" > /dev/null 2>&1
|
||||
echo -e "\033[0;32mAT Socat Bridge services removed!...\033[0m"
|
||||
fi
|
||||
|
||||
# Uninstall ttyd
|
||||
echo -e "\e[1;32mDo you want to uninstall ttyd (simpleadmin console)?\e[0m"
|
||||
echo -e "\e[1;31mWarning: Do not uninstall if you are currently using ttyd to do this!!!\e[0m"
|
||||
echo -e "\e[1;32m1) Yes\e[0m"
|
||||
echo -e "\e[1;31m2) No\e[0m"
|
||||
read -p "Enter your choice (1 or 2): " choice_simpleadmin
|
||||
if [ "$choice_simpleadmin" -eq 1 ]; then
|
||||
echo -e "\e[1;34mUninstalling ttyd...\e[0m"
|
||||
systemctl stop ttyd
|
||||
rm -rf /usrdata/ttyd
|
||||
rm /lib/systemd/system/ttyd.service
|
||||
rm /lib/systemd/system/multi-user.target.wants/ttyd.service
|
||||
rm /bin/ttyd
|
||||
echo -e "\e[1;32mttyd has been uninstalled.\e[0m"
|
||||
fi
|
||||
|
||||
echo "Uninstalling the rest of Simpleadmin..."
|
||||
|
||||
# Check if Lighttpd service is installed and remove it if present
|
||||
if [ -f "/lib/systemd/system/lighttpd.service" ]; then
|
||||
echo "Lighttpd detected, uninstalling Lighttpd and its modules..."
|
||||
systemctl stop lighttpd
|
||||
opkg --force-remove --force-removal-of-dependent-packages remove lighttpd-mod-authn_file lighttpd-mod-auth lighttpd-mod-cgi lighttpd-mod-openssl lighttpd-mod-proxy lighttpd
|
||||
rm -rf $LIGHTTPD_DIR
|
||||
fi
|
||||
|
||||
systemctl stop simpleadmin_generate_status
|
||||
systemctl stop simpleadmin_httpd
|
||||
rm -f /lib/systemd/system/simpleadmin_httpd.service
|
||||
rm -f /lib/systemd/system/simpleadmin_generate_status.service
|
||||
systemctl daemon-reload
|
||||
rm -rf "$SIMPLE_ADMIN_DIR"
|
||||
echo "The rest of Simpleadmin and Lighttpd (if present) uninstalled."
|
||||
remount_ro
|
||||
|
||||
echo "Uninstallation process completed."
|
||||
}
|
||||
|
||||
# Function for Tailscale Submenu
|
||||
tailscale_menu() {
|
||||
while true; do
|
||||
echo -e "\e[1;32mTailscale Menu\e[0m"
|
||||
echo -e "\e[1;32m1) Install/Update Tailscale\e[0m"
|
||||
echo -e "\e[1;36m2) Configure Tailscale\e[0m"
|
||||
echo -e "\e[1;31m3) Return to Main Menu\e[0m"
|
||||
read -p "Enter your choice: " tailscale_choice
|
||||
|
||||
case $tailscale_choice in
|
||||
1) install_update_tailscale;;
|
||||
2) configure_tailscale;;
|
||||
3) break;;
|
||||
*) echo "Invalid option";;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Function to install, update, or remove Tailscale
|
||||
install_update_tailscale() {
|
||||
echo -e "\e[1;31m2) Installing tailscale from the $GITTREE branch\e[0m"
|
||||
ensure_entware_installed
|
||||
mkdir /usrdata/simpleupdates > /dev/null 2>&1
|
||||
mkdir /usrdata/simpleupdates/scripts > /dev/null 2>&1
|
||||
wget -O /usrdata/simpleupdates/scripts/update_tailscale.sh https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleupdates/scripts/update_tailscale.sh && chmod +x /usrdata/simpleupdates/scripts/update_tailscale.sh
|
||||
echo -e "\e[1;32mInstalling/updating: Tailscale\e[0m"
|
||||
echo -e "\e[1;32mPlease Wait....\e[0m"
|
||||
remount_rw
|
||||
/usrdata/simpleupdates/scripts/update_tailscale.sh
|
||||
echo -e "\e[1;32m Tailscale has been updated/installed.\e[0m"
|
||||
}
|
||||
|
||||
# Function to Configure Tailscale
|
||||
configure_tailscale() {
|
||||
while true; do
|
||||
echo "Configure Tailscale"
|
||||
echo -e "\e[38;5;40m1) Enable Tailscale Web UI at http://192.168.225.1:8088 (Gateway on port 8088)\e[0m" # Green
|
||||
echo -e "\e[38;5;196m2) Disable Tailscale Web UI\e[0m" # Red
|
||||
echo -e "\e[38;5;27m3) Connect to Tailnet\e[0m" # Brown
|
||||
echo -e "\e[38;5;87m4) Connect to Tailnet with SSH ON\e[0m" # Light cyan
|
||||
echo -e "\e[38;5;105m5) Reconnect to Tailnet with SSH OFF\e[0m" # Light magenta
|
||||
echo -e "\e[38;5;172m6) Disconnect from Tailnet (reconnects at reboot)\e[0m" # Light yellow
|
||||
echo -e "\e[1;31m7) Logout from tailscale account\e[0m"
|
||||
echo -e "\e[38;5;27m8) Return to Tailscale Menu\e[0m"
|
||||
read -p "Enter your choice: " config_choice
|
||||
|
||||
case $config_choice in
|
||||
1)
|
||||
remount_rw
|
||||
cd /lib/systemd/system/
|
||||
wget -O tailscale-webui.service https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/main/tailscale/systemd/tailscale-webui.service
|
||||
wget -O tailscale-webui-trigger.service https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/main/tailscale/systemd/tailscale-webui-trigger.service
|
||||
ln -sf /lib/systemd/system/tailscale-webui-trigger.service /lib/systemd/system/multi-user.target.wants/
|
||||
systemctl daemon-reload
|
||||
echo "Tailscale Web UI Enabled"
|
||||
echo "Starting Web UI..."
|
||||
systemctl start tailscale-webui
|
||||
echo "Web UI started!"
|
||||
remount_ro
|
||||
;;
|
||||
2)
|
||||
remount_rw
|
||||
systemctl stop tailscale-webui
|
||||
systemctl disable tailscale-webui-trigger
|
||||
rm /lib/systemd/system/multi-user.target.wants/tailscale-webui.service
|
||||
rm /lib/systemd/system/multi-user.target.wants/tailscale-webui-trigger.service
|
||||
rm /lib/systemd/system/tailscale-webui.service
|
||||
rm /lib/systemd/system/tailscale-webui-trigger.service
|
||||
systemctl daemon-reload
|
||||
echo "Tailscale Web UI Stopped and Disabled"
|
||||
remount_ro
|
||||
;;
|
||||
3) $TAILSCALE_DIR/tailscale up --accept-dns=false --reset;;
|
||||
4) $TAILSCALE_DIR/tailscale up --ssh --accept-dns=false --reset;;
|
||||
5) $TAILSCALE_DIR/tailscale up --accept-dns=false --reset;;
|
||||
6) $TAILSCALE_DIR/tailscale down;;
|
||||
7) $TAILSCALE_DIR/tailscale logout;;
|
||||
8) break;;
|
||||
*) echo "Invalid option";;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Function to manage Daily Reboot Timer
|
||||
manage_reboot_timer() {
|
||||
# Remount root filesystem as read-write
|
||||
mount -o remount,rw /
|
||||
|
||||
# Check if the rebootmodem service, timer, or trigger already exists
|
||||
if [ -f /lib/systemd/system/rebootmodem.service ] || [ -f /lib/systemd/system/rebootmodem.timer ] || [ -f /lib/systemd/system/rebootmodem-trigger.service ]; then
|
||||
echo -e "\e[1;32mThe rebootmodem service/timer/trigger is already installed.\e[0m"
|
||||
echo -e "\e[1;32m1) Change\e[0m" # Green
|
||||
echo -e "\e[1;31m2) Remove\e[0m" # Red
|
||||
read -p "Enter your choice (1 for Change, 2 for Remove): " reboot_choice
|
||||
|
||||
case $reboot_choice in
|
||||
2)
|
||||
# Stop and disable timer and trigger service by removing symlinks
|
||||
systemctl stop rebootmodem.timer
|
||||
systemctl stop rebootmodem-trigger.service
|
||||
|
||||
# Remove symbolic links and files
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/rebootmodem-trigger.service
|
||||
rm -f /lib/systemd/system/rebootmodem.service
|
||||
rm -f /lib/systemd/system/rebootmodem.timer
|
||||
rm -f /lib/systemd/system/rebootmodem-trigger.service
|
||||
rm -f "$USRDATA_DIR/reboot_modem.sh"
|
||||
|
||||
# Reload systemd to apply changes
|
||||
systemctl daemon-reload
|
||||
|
||||
echo -e "\e[1;32mRebootmodem service, timer, trigger, and script removed successfully.\e[0m"
|
||||
;;
|
||||
1)
|
||||
printf "Enter the new time for daily reboot (24-hour format in Coordinated Universal Time, HH:MM): "
|
||||
read new_time
|
||||
|
||||
# Validate the new time format using grep
|
||||
if ! echo "$new_time" | grep -qE '^([01]?[0-9]|2[0-3]):[0-5][0-9]$'; then
|
||||
echo "Invalid time format. Exiting."
|
||||
exit 1
|
||||
else
|
||||
# Remove old symlinks and script
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/rebootmodem-trigger.service
|
||||
rm -f "$USRDATA_DIR/reboot_modem.sh"
|
||||
|
||||
# Set the user time to the new time and recreate the service, timer, trigger, and script
|
||||
user_time=$new_time
|
||||
create_service_and_timer
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo -e "\e[1;31mInvalid choice. Exiting.\e[0m"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
else
|
||||
printf "Enter the time for daily reboot (24-hour format in UTC, HH:MM): "
|
||||
read user_time
|
||||
|
||||
# Validate the time format using grep
|
||||
if ! echo "$user_time" | grep -qE '^([01]?[0-9]|2[0-3]):[0-5][0-9]$'; then
|
||||
echo "Invalid time format. Exiting."
|
||||
exit 1
|
||||
else
|
||||
create_service_and_timer
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remount root filesystem as read-only
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
# Function to create systemd service and timer files with the user-specified time for the reboot timer
|
||||
create_service_and_timer() {
|
||||
remount_rw
|
||||
# Define the path for the modem reboot script
|
||||
MODEM_REBOOT_SCRIPT="$USRDATA_DIR/reboot_modem.sh"
|
||||
|
||||
# Create the modem reboot script
|
||||
echo "#!/bin/sh
|
||||
/bin/echo -e 'AT+CFUN=1,1 \r' > /dev/smd7" > "$MODEM_REBOOT_SCRIPT"
|
||||
|
||||
# Make the script executable
|
||||
chmod +x "$MODEM_REBOOT_SCRIPT"
|
||||
|
||||
# Create the systemd service file for reboot
|
||||
echo "[Unit]
|
||||
Description=Reboot Modem Daily
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/sh /usrdata/reboot_modem.sh
|
||||
Restart=no
|
||||
RemainAfterExit=no" > /lib/systemd/system/rebootmodem.service
|
||||
|
||||
# Create the systemd timer file with the user-specified time
|
||||
echo "[Unit]
|
||||
Description=Starts rebootmodem.service daily at the specified time
|
||||
|
||||
[Timer]
|
||||
OnCalendar=*-*-* $user_time:00
|
||||
Persistent=false" > /lib/systemd/system/rebootmodem.timer
|
||||
|
||||
# Create a trigger service that starts the timer at boot
|
||||
echo "[Unit]
|
||||
Description=Trigger the rebootmodem timer at boot
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/systemctl start rebootmodem.timer
|
||||
RemainAfterExit=yes" > /lib/systemd/system/rebootmodem-trigger.service
|
||||
|
||||
# Create symbolic links for the trigger service in the wanted directory
|
||||
ln -sf /lib/systemd/system/rebootmodem-trigger.service /lib/systemd/system/multi-user.target.wants/
|
||||
|
||||
# Reload systemd to recognize the new timer and trigger service
|
||||
systemctl daemon-reload
|
||||
sleep 2s
|
||||
|
||||
# Start the trigger service, which will start the timer
|
||||
systemctl start rebootmodem-trigger.service
|
||||
remount_ro
|
||||
|
||||
# Confirmation
|
||||
echo -e "\e[1;32mRebootmodem-trigger service created and started successfully.\e[0m"
|
||||
echo -e "\e[1;32mReboot schedule set successfully. The modem will reboot daily at $user_time UTC.\e[0m"
|
||||
}
|
||||
|
||||
manage_cfun_fix() {
|
||||
cfun_service_path="/lib/systemd/system/cfunfix.service"
|
||||
cfun_fix_script="/usrdata/cfun_fix.sh"
|
||||
|
||||
mount -o remount,rw /
|
||||
|
||||
if [ -f "$cfun_service_path" ]; then
|
||||
echo -e "\e[1;32mThe CFUN fix is already installed. Do you want to remove it?\e[0m" # Green
|
||||
echo -e "\e[1;32m1) Yes\e[0m" # Green
|
||||
echo -e "\e[1;31m2) No\e[0m" # Red
|
||||
read -p "Enter your choice: " choice
|
||||
|
||||
if [ "$choice" = "1" ]; then
|
||||
echo "Removing CFUN fix..."
|
||||
systemctl stop cfunfix.service
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/cfunfix.service
|
||||
rm -f "$cfun_service_path"
|
||||
rm -f "$cfun_fix_script"
|
||||
systemctl daemon-reload
|
||||
echo "CFUN fix has been removed."
|
||||
else
|
||||
echo "Returning to main menu..."
|
||||
fi
|
||||
else
|
||||
echo -e "\e[1;32mInstalling CFUN fix...\e[0m"
|
||||
|
||||
# Create the CFUN fix script
|
||||
echo "#!/bin/sh
|
||||
/bin/echo -e 'AT+CFUN=1 \r' > /dev/smd7" > "$cfun_fix_script"
|
||||
chmod +x "$cfun_fix_script"
|
||||
|
||||
# Create the systemd service file to execute the CFUN fix script at boot
|
||||
echo "[Unit]
|
||||
Description=CFUN Fix Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=$cfun_fix_script
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target" > "$cfun_service_path"
|
||||
|
||||
ln -sf "$cfun_service_path" "/lib/systemd/system/multi-user.target.wants/"
|
||||
systemctl daemon-reload
|
||||
mount -o remount,ro /
|
||||
echo -e "\e[1;32mCFUN fix has been installed and will execute at every boot.\e[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
install_sshd() {
|
||||
if [ -d "/usrdata/sshd" ]; then
|
||||
echo -e "\e[1;31mSSHD is currently installed.\e[0m"
|
||||
echo -e "Do you want to update or uninstall?"
|
||||
echo -e "1.) Update"
|
||||
echo -e "2.) Uninstall"
|
||||
read -p "Select an option (1 or 2): " sshd_choice
|
||||
|
||||
case $sshd_choice in
|
||||
1)
|
||||
echo -e "\e[1;31m2) Installing sshd from the $GITTREE branch\e[0m"
|
||||
;;
|
||||
2)
|
||||
echo -e "\e[1;31mUninstalling SSHD...\e[0m"
|
||||
systemctl stop sshd
|
||||
rm /lib/systemd/system/sshd.service
|
||||
opkg remove openssh-server-pam
|
||||
echo -e "\e[1;32mSSHD has been uninstalled successfully.\e[0m"
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo -e "\e[1;31mInvalid option. Please select 1 or 2.\e[0m"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Proceed with installation or updating if not uninstalling
|
||||
ensure_entware_installed
|
||||
mkdir /usrdata/simpleupdates > /dev/null 2>&1
|
||||
mkdir /usrdata/simpleupdates/scripts > /dev/null 2>&1
|
||||
wget -O /usrdata/simpleupdates/scripts/update_sshd.sh https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleupdates/scripts/update_sshd.sh && chmod +x /usrdata/simpleupdates/scripts/update_sshd.sh
|
||||
echo -e "\e[1;32mInstalling/updating: SSHd\e[0m"
|
||||
echo -e "\e[1;32mPlease Wait....\e[0m"
|
||||
/usrdata/simpleupdates/scripts/update_sshd.sh
|
||||
echo -e "\e[1;32m SSHd has been updated/installed.\e[0m"
|
||||
}
|
||||
|
||||
|
||||
# Main menu
|
||||
while true; do
|
||||
echo " .%+: "
|
||||
echo " .*@@@-. "
|
||||
echo " :@@@@- "
|
||||
echo " @@@@#. "
|
||||
echo " -@@@@#. "
|
||||
echo " :. %@@@@: -# "
|
||||
echo " .+- #@@@@%.+@- "
|
||||
echo " .#- . +@@@@# #@- "
|
||||
echo " -@*@*@% @@@@@::@@= "
|
||||
echo ".+%@@@@@@@@@%=. =@@@@# #@@- .. "
|
||||
echo " .@@@@@: :@@@@@ =@@@..%= "
|
||||
echo " -::@-.+. @@@@@.=@@@- =@- "
|
||||
echo " .@- .@@@@@:.@@@* @@. "
|
||||
echo " .%- -@@@@@:=@@@@ @@# "
|
||||
echo " .#- .%@@@@@@#. +@@@@@.#@@@@ @@@."
|
||||
echo " .*- .@@@@@@@@@@=. @@@@@@ @@@@@ @@@:"
|
||||
echo " :. .%@@@@@@@@@@@%. .@@@@@+:@@@@@ @@@-"
|
||||
echo " -@@@@@@@@@@@@@@@..@@@@@@.-@@@@@ .@@@-"
|
||||
echo " -@@@@@@@@@@%. .@@@@@@. @@@@@+ =@@@="
|
||||
echo " =@@@@@@@@* .@@@@@@. @@@@@@..@@@@-"
|
||||
echo " #@@@@@@@@-*@@@@@%..@@@@@@+ #@@@@-"
|
||||
echo " @@@@@@:.-@@@@@@. @@@@@@= %@@@@@."
|
||||
echo " .@@@@. *@@@@@@- .+@@@@@@-.@@@@@@+ "
|
||||
echo " %@@. =@@@@@*. +@@@@@@%.-@@@@@@% "
|
||||
echo " .@@ .@@@@@= :@@@@@@@@..@@@@@@@= "
|
||||
echo " =@.+@@@@@. -@@@@@@@*.:@@@@@@@*. "
|
||||
echo " %.*@@@@= .@@@@@@@-.:@@@@@@@+. "
|
||||
echo " ..@@@@= .@@@@@@: #@@@@@@@: "
|
||||
echo " .@@@@ +@@@@..%@@@@@+. "
|
||||
echo " .@@@. @@@@.:@@@@+. "
|
||||
echo " @@@. @@@. @@@* .@. "
|
||||
echo " :@@@ %@@..@@#. *@ "
|
||||
echo " -*: .@@* :@@. @@. -..@@ "
|
||||
echo " =@@@@@@.*@- :@% @* =@:=@# "
|
||||
echo " .@@@-+@@@@:%@..%- ...@%:@@: "
|
||||
echo " .@@. @@-%@: .%@@*@@%. "
|
||||
echo " :@@ :+ *@ *@@#*@@@. "
|
||||
echo " =@@@.@@@@ "
|
||||
echo " .*@@@:=@@@@: "
|
||||
echo " .@@@@:.@@@@@: "
|
||||
echo " .@@@@#.-@@@@@. "
|
||||
echo " #@@@@: =@@@@@- "
|
||||
echo " .@@@@@..@@@@@@* "
|
||||
echo " -@@@@@. @@@@@@#. "
|
||||
echo " -@@@@@ @@@@@@% "
|
||||
echo " @@@@@. #@@@@@@. "
|
||||
echo " :@@@@# =@@@@@@% "
|
||||
echo " @@@@@: @@@@@@@: "
|
||||
echo " *@@@@ @@@@@@@. "
|
||||
echo " .@@@@ @@@@@@@ "
|
||||
echo " #@@@. @@@@@@* "
|
||||
echo " @@@# @@@@@@@ "
|
||||
echo " .@@+=@@@@@@. "
|
||||
echo " *@@@@@@ "
|
||||
echo " :@@@@@= "
|
||||
echo " .@@@@@@. "
|
||||
echo " :@@@@@*. "
|
||||
echo " .=@@@@@- "
|
||||
echo " :+##+. "
|
||||
|
||||
echo -e "\e[92m"
|
||||
echo "Welcome to iamromulan's RGMII Toolkit script for Quectel RMxxx Series modems!"
|
||||
echo "Visit https://github.com/iamromulan for more!"
|
||||
echo -e "\e[0m"
|
||||
echo "Select an option:"
|
||||
echo -e "\e[0m"
|
||||
echo -e "\e[96m1) Send AT Commands\e[0m" # Cyan
|
||||
echo -e "\e[93m2) Install Simple Admin\e[0m" # Yellow
|
||||
echo -e "\e[95m3) Set Simpleadmin (admin) password\e[0m" # Light Purple
|
||||
echo -e "\e[94m4) Set Console/ttyd (root) password\e[0m" # Light Blue
|
||||
echo -e "\e[91m5) Uninstall Simple Admin\e[0m" # Light Red
|
||||
echo -e "\e[95m6) Simple Firewall Management\e[0m" # Light Purple
|
||||
echo -e "\e[94m7) Tailscale Management\e[0m" # Light Blue
|
||||
echo -e "\e[92m8) Install/Change or remove Daily Reboot Timer\e[0m" # Light Green
|
||||
echo -e "\e[96m9) Install/Uninstall CFUN 0 Fix\e[0m" # Cyan (repeated color for additional options)
|
||||
echo -e "\e[91m10) Uninstall Entware/OPKG\e[0m" # Light Red
|
||||
echo -e "\e[92m11) Install Speedtest.net CLI app (speedtest command)\e[0m" # Light Green
|
||||
echo -e "\e[92m12) Install Fast.com CLI app (fast command)(tops out at 40Mbps)\e[0m" # Light Green
|
||||
echo -e "\e[92m13) Install OpenSSH Server\e[0m" # Light Green
|
||||
echo -e "\e[93m14) Exit\e[0m" # Yellow (repeated color for exit option)
|
||||
read -p "Enter your choice: " choice
|
||||
|
||||
case $choice in
|
||||
1)
|
||||
send_at_commands
|
||||
;;
|
||||
2)
|
||||
install_simple_admin
|
||||
;;
|
||||
3) set_simpleadmin_passwd
|
||||
;;
|
||||
4)
|
||||
set_root_passwd
|
||||
;;
|
||||
5)
|
||||
uninstall_simpleadmin_components
|
||||
;;
|
||||
6)
|
||||
configure_simple_firewall
|
||||
;;
|
||||
|
||||
7)
|
||||
tailscale_menu
|
||||
;;
|
||||
8)
|
||||
manage_reboot_timer
|
||||
;;
|
||||
9)
|
||||
manage_cfun_fix
|
||||
;;
|
||||
10)
|
||||
echo -e "\033[31mAre you sure you want to uninstall entware?\033[0m"
|
||||
echo -e "\033[31m1) Yes\033[0m"
|
||||
echo -e "\033[31m2) No\033[0m"
|
||||
read -p "Select an option (1 or 2): " user_choice
|
||||
|
||||
case $user_choice in
|
||||
1)
|
||||
# If yes, uninstall existing entware
|
||||
echo -e "\033[31mUninstalling existing entware...\033[0m"
|
||||
uninstall_entware # Assuming uninstall_entware is a defined function or command
|
||||
echo -e "\033[31mEntware has been uninstalled.\033[0m"
|
||||
;;
|
||||
2)
|
||||
# If no, exit the script
|
||||
echo -e "\033[31mUninstallation cancelled.\033[0m"
|
||||
exit # Use 'exit' to terminate the script outside a loop
|
||||
;;
|
||||
*)
|
||||
# Handle invalid input
|
||||
echo -e "\033[31mInvalid option. Please select 1 or 2.\033[0m"
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
|
||||
11)
|
||||
ensure_entware_installed
|
||||
echo -e "\e[1;32mInstalling Speedtest.net CLI (speedtest command)\e[0m"
|
||||
remount_rw
|
||||
mkdir /usrdata/root
|
||||
mkdir /usrdata/root/bin
|
||||
cd /usrdata/root/bin
|
||||
wget https://install.speedtest.net/app/cli/ookla-speedtest-1.2.0-linux-armhf.tgz
|
||||
tar -xzf ookla-speedtest-1.2.0-linux-armhf.tgz
|
||||
rm ookla-speedtest-1.2.0-linux-armhf.tgz
|
||||
rm speedtest.md
|
||||
cd /
|
||||
ln -sf /usrdata/root/bin/speedtest /bin
|
||||
remount_ro
|
||||
echo -e "\e[1;32mSpeedtest CLI (speedtest command) installed!!\e[0m"
|
||||
echo -e "\e[1;32mTry running the command 'speedtest'\e[0m"
|
||||
echo -e "\e[1;32mNote that it will not work unless you login to the root account first\e[0m"
|
||||
echo -e "\e[1;32mNormaly only an issue in adb, ttyd and ssh you are forced to login\e[0m"
|
||||
echo -e "\e[1;32mIf in adb just type login and then try to run the speedtest command\e[0m"
|
||||
;;
|
||||
12)
|
||||
echo -e "\e[1;32mInstalling fast.com CLI (fast command)\e[0m"
|
||||
remount_rw
|
||||
mkdir /usrdata/root
|
||||
mkdir /usrdata/root/bin
|
||||
cd /usrdata/root/bin
|
||||
wget -O fast https://github.com/ddo/fast/releases/download/v0.0.4/fast_linux_arm && chmod +x fast
|
||||
cd /
|
||||
ln -sf /usrdata/root/bin/fast /bin
|
||||
remount_ro
|
||||
echo -e "\e[1;32mFast.com CLI (speedtest command) installed!!\e[0m"
|
||||
echo -e "\e[1;32mTry running the command 'fast'\e[0m"
|
||||
echo -e "\e[1;32mThe fast.com test tops out at 40Mbps on the modem\e[0m"
|
||||
;;
|
||||
13)
|
||||
install_sshd
|
||||
;;
|
||||
14)
|
||||
echo -e "\e[1;32mGoodbye!\e[0m"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo -e "\e[1;31mInvalid option\e[0m"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
167
Belowx65Toolkit/installentware.sh
Normal file
167
Belowx65Toolkit/installentware.sh
Normal file
@@ -0,0 +1,167 @@
|
||||
#!/bin/sh
|
||||
# Modified by iamromulan to set up a proper entware environment for Quectel RM5xx series m.2 modems
|
||||
TYPE='generic'
|
||||
#|---------|-----------------|
|
||||
#| TARGET | Quectel Modem |
|
||||
#| ARCH | armv7sf-k3.2 |
|
||||
#| LOADER | ld-linux.so.3 |
|
||||
#| GLIBC | 2.27 |
|
||||
#|---------|-----------------|
|
||||
unset LD_LIBRARY_PATH
|
||||
unset LD_PRELOAD
|
||||
ARCH=armv7sf-k3.2
|
||||
LOADER=ld-linux.so.3
|
||||
GLIBC=2.27
|
||||
PRE_OPKG_PATH=$(which opkg)
|
||||
|
||||
# Remount filesystem as read-write
|
||||
mount -o remount,rw /
|
||||
|
||||
create_opt_mount() {
|
||||
# Bind /usrdata/opt to /opt
|
||||
echo -e '\033[32mInfo: Setting up /opt mount to /usrdata/opt...\033[0m'
|
||||
cat <<EOF > /lib/systemd/system/opt.mount
|
||||
[Unit]
|
||||
Description=Bind /usrdata/opt to /opt
|
||||
|
||||
[Mount]
|
||||
What=/usrdata/opt
|
||||
Where=/opt
|
||||
Type=none
|
||||
Options=bind
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl start opt.mount
|
||||
|
||||
# Additional systemd service to ensure opt.mount starts at boot
|
||||
echo -e '\033[32mInfo: Creating service to start opt.mount at boot...\033[0m'
|
||||
cat <<EOF > /lib/systemd/system/start-opt-mount.service
|
||||
[Unit]
|
||||
Description=Ensure opt.mount is started at boot
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/systemctl start opt.mount
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
ln -s /lib/systemd/system/start-opt-mount.service /lib/systemd/system/multi-user.target.wants/start-opt-mount.service
|
||||
}
|
||||
|
||||
if [ -n "$PRE_OPKG_PATH" ]; then
|
||||
# Automatically rename the existing opkg binary
|
||||
mv "$PRE_OPKG_PATH" "${PRE_OPKG_PATH}_old"
|
||||
echo -e "\033[32mFactory/Already existing opkg has been renamed to opkg_old.\033[0m"
|
||||
else
|
||||
echo "Info: no existing opkg binary detected, proceeding with installation"
|
||||
fi
|
||||
|
||||
echo -e '\033[32mInfo: Creating /opt mount pointed to /usrdata/opt ...\033[0m'
|
||||
create_opt_mount
|
||||
echo -e '\033[32mInfo: Proceeding with main installation ...\033[0m'
|
||||
# no need to create many folders. entware-opt package creates most
|
||||
for folder in bin etc lib/opkg tmp var/lock
|
||||
do
|
||||
if [ -d "/opt/$folder" ]; then
|
||||
echo -e '\033[31mWarning: Folder /opt/$folder exists!\033[0m'
|
||||
echo -e '\033[31mWarning: If something goes wrong please clean /opt folder and try again.\033[0m'
|
||||
else
|
||||
mkdir -p /opt/$folder
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e '\033[32mInfo: Opkg package manager deployment...\033[0m'
|
||||
URL=http://bin.entware.net/${ARCH}/installer
|
||||
wget $URL/opkg -O /opt/bin/opkg
|
||||
chmod 755 /opt/bin/opkg
|
||||
wget $URL/opkg.conf -O /opt/etc/opkg.conf
|
||||
|
||||
echo -e '\033[32mInfo: Basic packages installation...\033[0m'
|
||||
/opt/bin/opkg update
|
||||
/opt/bin/opkg install entware-opt
|
||||
|
||||
# Fix for multiuser environment
|
||||
chmod 777 /opt/tmp
|
||||
|
||||
for file in passwd group shells shadow gshadow; do
|
||||
if [ $TYPE = 'generic' ]; then
|
||||
if [ -f /etc/$file ]; then
|
||||
ln -sf /etc/$file /opt/etc/$file
|
||||
else
|
||||
[ -f /opt/etc/$file.1 ] && cp /opt/etc/$file.1 /opt/etc/$file
|
||||
fi
|
||||
else
|
||||
if [ -f /opt/etc/$file.1 ]; then
|
||||
cp /opt/etc/$file.1 /opt/etc/$file
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
[ -f /etc/localtime ] && ln -sf /etc/localtime /opt/etc/localtime
|
||||
|
||||
# Create and enable rc.unslung service
|
||||
echo -e '\033[32mInfo: Creating rc.unslung (Entware init.d service)...\033[0m'
|
||||
cat <<EOF > /lib/systemd/system/rc.unslung.service
|
||||
[Unit]
|
||||
Description=Start Entware services
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
# Add a delay to give /opt time to mount
|
||||
ExecStartPre=/bin/sleep 5
|
||||
ExecStart=/opt/etc/init.d/rc.unslung start
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
systemctl daemon-reload
|
||||
ln -s /lib/systemd/system/rc.unslung.service /lib/systemd/system/multi-user.target.wants/rc.unslung.service
|
||||
systemctl start rc.unslung.service
|
||||
echo -e '\033[32mInfo: Congratulations!\033[0m'
|
||||
echo -e '\033[32mInfo: If there are no errors above then Entware was successfully initialized.\033[0m'
|
||||
echo -e '\033[32mInfo: Add /opt/bin & /opt/sbin to $PATH variable\033[0m'
|
||||
ln -sf /opt/bin/opkg /bin
|
||||
echo -e '\033[32mInfo: Patching Quectel Login Binary\033[0m'
|
||||
opkg update && opkg install shadow-login shadow-passwd shadow-useradd
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo -e "\e[1;31mPackage installation failed. Please check your internet connection and try again.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Replace the login and passwd binaries and set home for root to a writable directory
|
||||
rm /opt/etc/shadow
|
||||
rm /opt/etc/passwd
|
||||
cp /etc/shadow /opt/etc/
|
||||
cp /etc/passwd /opt/etc
|
||||
mkdir /usrdata/root
|
||||
mkdir /usrdata/root/bin
|
||||
touch /usrdata/root/.profile
|
||||
echo "# Set PATH for all shells" > /usrdata/root/.profile
|
||||
echo "export PATH=/bin:/usr/sbin:/usr/bin:/sbin:/opt/sbin:/opt/bin:/usrdata/root/bin" >> /usrdata/root/.profile
|
||||
chmod +x /usrdata/root/.profile
|
||||
sed -i '1s|/home/root:/bin/sh|/usrdata/root:/bin/bash|' /opt/etc/passwd
|
||||
rm /bin/login /usr/bin/passwd
|
||||
ln -sf /opt/bin/login /bin
|
||||
ln -sf /opt/bin/passwd /usr/bin/
|
||||
ln -sf /opt/bin/useradd /usr/bin/
|
||||
echo -e "\e[1;31mPlease set the root password.\e[0m"
|
||||
/usr/bin/passwd
|
||||
|
||||
# Install basic and useful utilites
|
||||
opkg install mc htop dfc lsof
|
||||
ln -sf /opt/bin/mc /bin
|
||||
ln -sf /opt/bin/htop /bin
|
||||
ln -sf /opt/bin/dfc /bin
|
||||
ln -sf /opt/bin/lsof /bin
|
||||
# Remount filesystem as read-only
|
||||
mount -o remount,ro /
|
||||
1
Belowx65Toolkit/simpleadmin/.rev
Normal file
1
Belowx65Toolkit/simpleadmin/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
7
Belowx65Toolkit/simpleadmin/console/.profile
Normal file
7
Belowx65Toolkit/simpleadmin/console/.profile
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
#Path
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
|
||||
#Post-login execution
|
||||
/usrdata/simpleadmin/console/menu/start_menu.sh
|
||||
150
Belowx65Toolkit/simpleadmin/console/menu/LAN_settings.sh
Normal file
150
Belowx65Toolkit/simpleadmin/console/menu/LAN_settings.sh
Normal file
@@ -0,0 +1,150 @@
|
||||
#!/bin/bash
|
||||
|
||||
CONFIG_FILE="/etc/data/mobileap_cfg.xml"
|
||||
|
||||
# Display Messages in Colors
|
||||
display_random_color() {
|
||||
local msg="$1"
|
||||
local colors=(33 34 35 36 37) # ANSI color codes for yellow, blue, magenta, cyan, white
|
||||
local num_colors=${#colors[@]}
|
||||
local random_color_index=$(($RANDOM % num_colors)) # Pick a random index from the colors array
|
||||
echo -e "\033[${colors[$random_color_index]}m$msg\033[0m"
|
||||
}
|
||||
|
||||
display_green() {
|
||||
echo -e "\033[0;32m$1\033[0m"
|
||||
}
|
||||
|
||||
display_red() {
|
||||
echo -e "\033[0;31m$1\033[0m"
|
||||
}
|
||||
|
||||
# Check and Install xml binary if not present
|
||||
check_and_install_xml() {
|
||||
if [ ! -f "/opt/bin/xml" ]; then
|
||||
echo "xml binary not found. Attempting to install xmlstarlet..."
|
||||
opkg update
|
||||
opkg install xmlstarlet
|
||||
# Verify installation
|
||||
if [ ! -f "/opt/bin/xml" ]; then
|
||||
echo "Failed to install xmlstarlet. Exiting..."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo "xml binary is available."
|
||||
}
|
||||
|
||||
# Edit XML Value
|
||||
edit_xml_value() {
|
||||
local node="$1"
|
||||
local new_value="$2"
|
||||
/opt/bin/xml ed -L -u "$node" -v "$new_value" "$CONFIG_FILE"
|
||||
}
|
||||
|
||||
# Get Current XML Value
|
||||
get_current_value() {
|
||||
/opt/bin/xml sel -t -v "$1" "$CONFIG_FILE"
|
||||
}
|
||||
|
||||
# Enable/Disable Menu
|
||||
enable_disable_menu() {
|
||||
local node="$1"
|
||||
local current_value=$(get_current_value "$node")
|
||||
echo "Current status: $([ "$current_value" == "1" ] && echo "Enabled" || echo "Disabled")"
|
||||
echo "1. Enable"
|
||||
echo "2. Disable"
|
||||
read -p "Choose an option to toggle (1-2): " choice
|
||||
local new_value="$([ "$choice" == "1" ] && echo "1" || echo "0")"
|
||||
edit_xml_value "$node" "$new_value"
|
||||
display_green "After making changes, please reboot to have them take effect."
|
||||
}
|
||||
|
||||
# Edit Simple Value
|
||||
edit_simple_value() {
|
||||
local node="$1"
|
||||
local description="$2"
|
||||
local current=$(get_current_value "$node")
|
||||
echo "Current $description: $current"
|
||||
read -p "Enter new $description: " new_value
|
||||
edit_xml_value "$node" "$new_value"
|
||||
display_green "After making changes, please reboot to have them take effect."
|
||||
}
|
||||
|
||||
# Edit DHCP IP Range
|
||||
edit_dhcp_range() {
|
||||
local start_ip=$(get_current_value "//MobileAPLanCfg/DHCPCfg/StartIP")
|
||||
local end_ip=$(get_current_value "//MobileAPLanCfg/DHCPCfg/EndIP")
|
||||
echo "Current Start IP: $start_ip"
|
||||
echo "Current End IP: $end_ip"
|
||||
read -p "Enter new Start IP: " new_start_ip
|
||||
read -p "Enter new End IP: " new_end_ip
|
||||
edit_xml_value "//MobileAPLanCfg/DHCPCfg/StartIP" "$new_start_ip"
|
||||
edit_xml_value "//MobileAPLanCfg/DHCPCfg/EndIP" "$new_end_ip"
|
||||
display_green "After making changes, please reboot to have them take effect."
|
||||
}
|
||||
|
||||
# Reboot the system
|
||||
reboot_system() {
|
||||
echo "Rebooting system..."
|
||||
atcmd 'AT+CFUN=1,1' # Ensure this command is correct for your system
|
||||
echo "System reboot initiated. Good luck."
|
||||
}
|
||||
|
||||
# Main Menu
|
||||
main_menu() {
|
||||
while true; do
|
||||
clear
|
||||
display_red "Warning, these changes can break access over the network. Know what you are doing, and be prepared to use ADB to fix this just in case."
|
||||
echo "Configuration Menu"
|
||||
echo "------------------"
|
||||
display_green "1. Edit Gateway IPV4 Address"
|
||||
display_green "2. Edit Gateway URL"
|
||||
display_green "3. Edit LAN DHCP Start/End Range"
|
||||
display_green "4. Edit LAN Subnet Mask"
|
||||
display_green "5. Edit DHCPv6 Base address"
|
||||
display_green "6. Toggle IPv4 NAT"
|
||||
display_green "7. Toggle IPv6 NAT"
|
||||
display_green "8. Toggle DHCP Server"
|
||||
display_green "9. Toggle DHCPv4"
|
||||
display_green "10. Toggle DHCPv6"
|
||||
display_green "11. Toggle WAN Autoconnect"
|
||||
display_green "12. Toggle WAN AutoReconnect"
|
||||
display_green "13. Toggle Roaming"
|
||||
display_green "14. Toggle WAN DNSv4 Passthrough"
|
||||
display_green "15. Toggle WAN DNSv6 Passthrough"
|
||||
display_green "16. Toggle IPPT NAT/Ability to access gateway while in IPPT mode"
|
||||
display_green "17. Toggle UPnP"
|
||||
display_green "18. Reboot System"
|
||||
display_green "19. Exit"
|
||||
echo
|
||||
read -p "Select an option (1-19): " option
|
||||
|
||||
case "$option" in
|
||||
1) edit_simple_value "//MobileAPLanCfg/APIPAddr" "Gateway IPV4 Address";;
|
||||
2) edit_simple_value "//MobileAPLanCfg/GatewayURL" "Gateway URL";;
|
||||
3) edit_dhcp_range;;
|
||||
4) edit_simple_value "//MobileAPLanCfg/SubNetMask" "LAN Subnet Mask";;
|
||||
5) edit_simple_value "//MobileAPLanCfg/ULAIPv6BaseAddr" "DHCPv6 Base Address";;
|
||||
6) enable_disable_menu "//MobileAPNatCfg/IPv4NATDisable";;
|
||||
7) enable_disable_menu "//MobileAPNatv6Cfg/EnableIPv6NAT";;
|
||||
8) enable_disable_menu "//MobileAPLanCfg/EnableDHCPServer";;
|
||||
9) enable_disable_menu "//MobileAPLanCfg/EnableIPV4";;
|
||||
10) enable_disable_menu "//MobileAPLanCfg/EnableIPV6";;
|
||||
11) enable_disable_menu "//MobileAPWanCfg/AutoConnect";;
|
||||
12) enable_disable_menu "//MobileAPWanCfg/ReConnect";;
|
||||
13) enable_disable_menu "//MobileAPWanCfg/Roaming";;
|
||||
14) enable_disable_menu "//Dhcpv4Cfg/EnableDhcpv4Dns";;
|
||||
15) enable_disable_menu "//Dhcpv6Cfg/EnableDhcpv6Dns";;
|
||||
16) enable_disable_menu "//IPPassthroughFeatureWithNAT";;
|
||||
17) enable_disable_menu "//MobileAPSrvcCfg/UPnP";;
|
||||
18) reboot_system;;
|
||||
19) break;;
|
||||
*) echo "Invalid option. Please try again.";;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# Start by checking and installing xml if necessary, then mount filesystem as rw and run the menu
|
||||
mount -o remount,rw /
|
||||
check_and_install_xml
|
||||
main_menu
|
||||
129
Belowx65Toolkit/simpleadmin/console/menu/sfirewall_settings.sh
Normal file
129
Belowx65Toolkit/simpleadmin/console/menu/sfirewall_settings.sh
Normal file
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
|
||||
SIMPLE_FIREWALL_DIR="/usrdata/simplefirewall"
|
||||
SIMPLE_FIREWALL_SCRIPT="$SIMPLE_FIREWALL_DIR/simplefirewall.sh"
|
||||
SIMPLE_FIREWALL_SYSTEMD_DIR="$SIMPLE_FIREWALL_DIR/systemd"
|
||||
|
||||
# Display Messages in Colors
|
||||
display_random_color() {
|
||||
local msg="$1"
|
||||
local colors=(33 34 35 36 37) # ANSI color codes for yellow, blue, magenta, cyan, white
|
||||
local num_colors=${#colors[@]}
|
||||
local random_color_index=$(($RANDOM % num_colors)) # Pick a random index from the colors array
|
||||
echo -e "\033[${colors[$random_color_index]}m$msg\033[0m"
|
||||
}
|
||||
|
||||
display_green() {
|
||||
echo -e "\033[0;32m$1\033[0m"
|
||||
}
|
||||
|
||||
display_red() {
|
||||
echo -e "\033[0;31m$1\033[0m"
|
||||
}
|
||||
|
||||
set_portblocks() {
|
||||
current_ports_line=$(grep '^PORTS=' "$SIMPLE_FIREWALL_SCRIPT")
|
||||
ports=$(echo "$current_ports_line" | cut -d'=' -f2 | tr -d '()' | tr ' ' '\n' | grep -o '[0-9]\+')
|
||||
echo -e "\e[1;32mCurrent configured ports:\e[0m"
|
||||
echo "$ports" | awk '{print NR") "$0}'
|
||||
|
||||
while true; do
|
||||
echo -e "\e[1;32mEnter a port number to add/remove, or type 'done' or 'exit' to finish:\e[0m"
|
||||
read port
|
||||
if [ "$port" = "done" ] || [ "$port" = "exit" ]; then
|
||||
if [ "$port" = "exit" ]; then
|
||||
echo -e "\e[1;31mExiting without making changes...\e[0m"
|
||||
return
|
||||
fi
|
||||
break
|
||||
elif ! echo "$port" | grep -qE '^[0-9]+$'; then
|
||||
echo -e "\e[1;31mInvalid input: Please enter a numeric value.\e[0m"
|
||||
elif echo "$ports" | grep -q "^$port\$"; then
|
||||
ports=$(echo "$ports" | grep -v "^$port\$")
|
||||
echo -e "\e[1;32mPort $port removed.\e[0m"
|
||||
else
|
||||
ports=$(echo "$ports"; echo "$port" | grep -o '[0-9]\+')
|
||||
echo -e "\e[1;32mPort $port added.\e[0m"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$port" != "exit" ]; then
|
||||
new_ports_line="PORTS=($(echo "$ports" | tr '\n' ' '))"
|
||||
sed -i "s/$current_ports_line/$new_ports_line/" "$SIMPLE_FIREWALL_SCRIPT"
|
||||
fi
|
||||
}
|
||||
|
||||
set_ttl(){
|
||||
# TTL configuration code
|
||||
ttl_value=$(cat /usrdata/simplefirewall/ttlvalue)
|
||||
if [ "$ttl_value" -eq 0 ]; then
|
||||
echo -e "\e[1;31mTTL is not set.\e[0m"
|
||||
else
|
||||
echo -e "\e[1;32mTTL value is set to $ttl_value.\e[0m"
|
||||
fi
|
||||
|
||||
echo -e "\e[1;31mType 'exit' to cancel.\e[0m"
|
||||
read -p "What do you want the TTL value to be: " new_ttl_value
|
||||
if [ "$new_ttl_value" = "exit" ]; then
|
||||
echo -e "\e[1;31mExiting TTL configuration...\e[0m"
|
||||
return
|
||||
elif ! echo "$new_ttl_value" | grep -qE '^[0-9]+$'; then
|
||||
echo -e "\e[1;31mInvalid input: Please enter a numeric value.\e[0m"
|
||||
return
|
||||
else
|
||||
/usrdata/simplefirewall/ttl-override stop
|
||||
echo "$new_ttl_value" > /usrdata/simplefirewall/ttlvalue
|
||||
/usrdata/simplefirewall/ttl-override start
|
||||
echo -e "\033[0;32mTTL value updated to $new_ttl_value.\033[0m"
|
||||
fi
|
||||
}
|
||||
|
||||
# function to configure the fetures of simplefirewall
|
||||
simple_firewall_menu() {
|
||||
if [ ! -f "$SIMPLE_FIREWALL_SCRIPT" ]; then
|
||||
display_random_color "Simplefirewall is not installed, would you like to install it?"
|
||||
display_green "1) Yes"
|
||||
display_red "2) No"
|
||||
read -p "Enter your choice (1-2): " install_choice
|
||||
|
||||
case $install_choice in
|
||||
1)
|
||||
install_simple_firewall
|
||||
;;
|
||||
2)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
display_red "Invalid choice. Please select either 1 or 2."
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
display_random_color "Configure Simple Firewall:"
|
||||
display_green "1) Configure incoming port block"
|
||||
display_green "2) Configure TTL"
|
||||
display_green "3) Exit to Main Menu"
|
||||
read -p "Enter your choice (1-2): " menu_choice
|
||||
|
||||
case $menu_choice in
|
||||
1)
|
||||
set_portblocks
|
||||
;;
|
||||
2)
|
||||
set_ttl
|
||||
;;
|
||||
3)
|
||||
return
|
||||
;;
|
||||
*)
|
||||
echo -e "\e[1;31mInvalid choice. Please select either 1 or 2.\e[0m"
|
||||
;;
|
||||
esac
|
||||
|
||||
systemctl restart simplefirewall
|
||||
echo -e "\e[1;32mFirewall configuration updated.\e[0m"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
mount -o remount,rw /
|
||||
simple_firewall_menu
|
||||
118
Belowx65Toolkit/simpleadmin/console/menu/start_menu.sh
Normal file
118
Belowx65Toolkit/simpleadmin/console/menu/start_menu.sh
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define executable files path
|
||||
MENU_SH=/usrdata/simpleadmin/console/menu
|
||||
|
||||
# Display Messages in Colors
|
||||
display_random_color() {
|
||||
local msg="$1"
|
||||
local colors=(33 34 35 36 37) # ANSI color codes for yellow, blue, magenta, cyan, white
|
||||
local num_colors=${#colors[@]}
|
||||
local random_color_index=$(($RANDOM % num_colors)) # Pick a random index from the colors array
|
||||
echo -e "\033[${colors[$random_color_index]}m$msg\033[0m"
|
||||
}
|
||||
|
||||
display_green() {
|
||||
echo -e "\033[0;32m$1\033[0m"
|
||||
}
|
||||
|
||||
display_red() {
|
||||
echo -e "\033[0;31m$1\033[0m"
|
||||
}
|
||||
|
||||
# Menus
|
||||
|
||||
toolkit_menu() {
|
||||
while true; do
|
||||
display_random_color "Run a Toolkit version"
|
||||
display_green "Select an option:"
|
||||
echo "------------------"
|
||||
display_green "1. Get and run the Toolkit"
|
||||
display_random_color "2. Get and run the Development/unstable Toolkit"
|
||||
display_random_color "3. Exit (Enter Root Shell)"
|
||||
echo
|
||||
read -p "Select an option (1-3): " option
|
||||
|
||||
case "$option" in
|
||||
1) cd /tmp && wget -O RMxxx_rgmii_toolkit.sh https://raw.githubusercontent.com/iamromulan/quectel-rgmii-toolkit/main/RMxxx_rgmii_toolkit.sh && chmod +x RMxxx_rgmii_toolkit.sh && ./RMxxx_rgmii_toolkit.sh && cd / ;;
|
||||
2) cd /tmp && wget -O RMxxx_rgmii_toolkit.sh https://raw.githubusercontent.com/iamromulan/quectel-rgmii-toolkit/development/RMxxx_rgmii_toolkit.sh && chmod +x RMxxx_rgmii_toolkit.sh && ./RMxxx_rgmii_toolkit.sh && cd / ;;
|
||||
3) break ;;
|
||||
*) echo "Invalid option. Please try again." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
apps_menu() {
|
||||
while true; do
|
||||
display_random_color "Run a modem App"
|
||||
display_green "Select an option:"
|
||||
echo "------------------"
|
||||
display_random_color "1. Open File Browser/Editor (mc)"
|
||||
display_random_color "2. View Used/Available space"
|
||||
display_random_color "3. Open Task Manager/View CPU Load"
|
||||
display_random_color "4. Run speedtest.net test"
|
||||
display_random_color "5. Run fast.com test (30Mbps max)"
|
||||
display_green "6. Go Back"
|
||||
echo
|
||||
read -p "Select an option (1-6): " option
|
||||
|
||||
case "$option" in
|
||||
1) mc ;;
|
||||
2) dfc ;;
|
||||
3) htop ;;
|
||||
4) speedtest ;;
|
||||
5) fast ;;
|
||||
6) break ;;
|
||||
*) echo "Invalid option. Please try again." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
settings_menu() {
|
||||
while true; do
|
||||
display_random_color "Welcome to" && display_green "iamromulan's" && display_random_color "Simple Console Menu"
|
||||
display_green "Select an option:"
|
||||
echo "------------------"
|
||||
display_green "1. LAN Settings"
|
||||
display_green "2. simplefirewall settings (TTL and Port Block)"
|
||||
display_green "3. Change simpleadmin (admin) password"
|
||||
display_green "4. Change root password (shell/ssh/console)"
|
||||
display_green "5. Go back"
|
||||
echo
|
||||
read -p "Select an option (1-5): " option
|
||||
|
||||
case "$option" in
|
||||
1) $MENU_SH/LAN_settings.sh ;;
|
||||
2) $MENU_SH/sfirewall_settings.sh ;;
|
||||
3) simplepasswd ;;
|
||||
4) passwd ;;
|
||||
5) break ;;
|
||||
*) echo "Invalid option. Please try again." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
while true; do
|
||||
display_green "Welcome to iamromulan's Simple Console Menu"
|
||||
display_green "To get back to this from the root shell, just type 'menu'"
|
||||
display_green "Select an option:"
|
||||
echo "------------------"
|
||||
display_random_color "1. Apps"
|
||||
display_random_color "2. Settings"
|
||||
display_random_color "3. Toolkit"
|
||||
display_random_color "4. Exit (Enter Root Shell)"
|
||||
echo
|
||||
read -p "Select an option (1-4): " option
|
||||
|
||||
case "$option" in
|
||||
1) apps_menu ;;
|
||||
2) settings_menu ;;
|
||||
3) toolkit_menu ;;
|
||||
4) break ;;
|
||||
*) echo "Invalid option. Please try again." ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
main_menu
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define the command to execute when the ethernet port breaks
|
||||
command_to_execute="/usrdata/socat-at-bridge/atcmd 'AT+CFUN=1,1'"
|
||||
|
||||
# Define the monitoring function
|
||||
watch() {
|
||||
while true; do
|
||||
# Extract the last 60 lines of dmesg and count the specific pattern occurrences
|
||||
count=$(dmesg | tail -60 | grep -e "eth0: cmd = 0xff, should be 0x47" -e "eth0: pci link is down" | grep -c "eth0")
|
||||
|
||||
# Check if the count of patterns is 4 or more
|
||||
if [ "$count" -ge 4 ]; then
|
||||
echo "Condition met, executing command..."
|
||||
eval "$command_to_execute"
|
||||
# Optionally, add a break here if you want the script to stop after executing the command
|
||||
# break
|
||||
fi
|
||||
|
||||
# Sleep for 3 seconds before checking again
|
||||
sleep 3
|
||||
done
|
||||
}
|
||||
|
||||
# Initial delay before starting monitoring
|
||||
sleep 30
|
||||
watch
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define the hostname or IP address to ping
|
||||
HOSTNAME="google.com"
|
||||
|
||||
# Number of pings to attempt
|
||||
PING_COUNT=6
|
||||
|
||||
# Initialize a counter for successful pings
|
||||
success_count=0
|
||||
|
||||
# Attempt to ping the specified number of times
|
||||
for i in $(seq 1 $PING_COUNT); do
|
||||
# Ping the hostname with a timeout of 1 second per ping
|
||||
if ping -c 1 -W 1 $HOSTNAME &> /dev/null; then
|
||||
((success_count++))
|
||||
else
|
||||
echo "Ping attempt $i failed."
|
||||
fi
|
||||
done
|
||||
|
||||
# Check if all pings failed
|
||||
if [ $success_count -eq 0 ]; then
|
||||
echo "All $PING_COUNT ping attempts failed, executing AT command."
|
||||
/bin/atcmd 'AT+CFUN=1,1'
|
||||
else
|
||||
echo "$success_count out of $PING_COUNT ping attempts were successful."
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Ping Watchdog Service
|
||||
Wants=network.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=/bin/sleep 60 # Sleep for 60 seconds to ensure the network is ready
|
||||
ExecStart=/usrdata/simpleadmin/console/services/ping_watchdog.sh
|
||||
Restart=on-failure
|
||||
RestartSec=30s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
99
Belowx65Toolkit/simpleadmin/console/ttyd.bash
Normal file
99
Belowx65Toolkit/simpleadmin/console/ttyd.bash
Normal file
@@ -0,0 +1,99 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check if /usrdata/socat-at-bridge/atcmd exists
|
||||
if [ -f "/usrdata/socat-at-bridge/atcmd" ]; then
|
||||
# Read the serial number
|
||||
serial_number=$(/usrdata/socat-at-bridge/atcmd 'AT+EGMR=0,5' | grep '+EGMR:' | cut -d '"' -f2)
|
||||
# Read the firmware revision
|
||||
firmware_revision=$(/usrdata/socat-at-bridge/atcmd 'AT+QGMR' | grep -o 'RM[0-9A-Z].*')
|
||||
else
|
||||
serial_number="UNKNOWN"
|
||||
firmware_revision="UNKNOWN"
|
||||
fi
|
||||
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
echo "=============================================================="
|
||||
# Start your Actual echo output here, 17 lines omitted for mobile compatibility. ttyd font needs to be size 25.
|
||||
# Echo "Logo"
|
||||
echo " .%+: "
|
||||
echo " .*@@@-. "
|
||||
echo " :@@@@- "
|
||||
echo " @@@@#. "
|
||||
echo " -@@@@#. "
|
||||
echo " :. %@@@@: -# "
|
||||
echo " .+- #@@@@%.+@- "
|
||||
echo " .#- . +@@@@# #@- "
|
||||
echo " -@*@*@% @@@@@::@@= "
|
||||
echo ".+%@@@@@@@@@%=. =@@@@# #@@- .. "
|
||||
echo " .@@@@@: :@@@@@ =@@@..%= "
|
||||
echo " -::@-.+. @@@@@.=@@@- =@- "
|
||||
echo " .@- .@@@@@:.@@@* @@. "
|
||||
echo " .%- -@@@@@:=@@@@ @@# "
|
||||
echo " .#- .%@@@@@@#. +@@@@@.#@@@@ @@@."
|
||||
echo " .*- .@@@@@@@@@@=. @@@@@@ @@@@@ @@@:"
|
||||
echo " :. .%@@@@@@@@@@@%. .@@@@@+:@@@@@ @@@-"
|
||||
echo " -@@@@@@@@@@@@@@@..@@@@@@.-@@@@@ .@@@-"
|
||||
echo " -@@@@@@@@@@%. .@@@@@@. @@@@@+ =@@@="
|
||||
echo " =@@@@@@@@* .@@@@@@. @@@@@@..@@@@-"
|
||||
echo " #@@@@@@@@-*@@@@@%..@@@@@@+ #@@@@-"
|
||||
echo " @@@@@@:.-@@@@@@. @@@@@@= %@@@@@."
|
||||
echo " .@@@@. *@@@@@@- .+@@@@@@-.@@@@@@+ "
|
||||
echo " %@@. =@@@@@*. +@@@@@@%.-@@@@@@% "
|
||||
echo " .@@ .@@@@@= :@@@@@@@@..@@@@@@@= "
|
||||
echo " =@.+@@@@@. -@@@@@@@*.:@@@@@@@*. "
|
||||
echo " %.*@@@@= .@@@@@@@-.:@@@@@@@+. "
|
||||
echo " ..@@@@= .@@@@@@: #@@@@@@@: "
|
||||
echo " .@@@@ +@@@@..%@@@@@+. "
|
||||
echo " .@@@. @@@@.:@@@@+. "
|
||||
echo " @@@. @@@. @@@* .@. "
|
||||
echo " :@@@ %@@..@@#. *@ "
|
||||
echo " -*: .@@* :@@. @@. -..@@ "
|
||||
echo " =@@@@@@.*@- :@% @* =@:=@# "
|
||||
echo " .@@@-+@@@@:%@..%- ...@%:@@: "
|
||||
echo " .@@. @@-%@: .%@@*@@%. "
|
||||
echo " :@@ :+ *@ *@@#*@@@. "
|
||||
echo " =@@@.@@@@ "
|
||||
echo " .*@@@:=@@@@: "
|
||||
echo " .@@@@:.@@@@@: "
|
||||
echo " .@@@@#.-@@@@@. "
|
||||
echo " #@@@@: =@@@@@- "
|
||||
echo " .@@@@@..@@@@@@* "
|
||||
echo " -@@@@@. @@@@@@#. "
|
||||
echo " -@@@@@ @@@@@@% "
|
||||
echo " @@@@@. #@@@@@@. "
|
||||
echo " :@@@@# =@@@@@@% "
|
||||
echo " @@@@@: @@@@@@@: "
|
||||
echo " *@@@@ @@@@@@@. "
|
||||
echo " .@@@@ @@@@@@@ "
|
||||
echo " #@@@. @@@@@@* "
|
||||
echo " @@@# @@@@@@@ "
|
||||
echo " .@@+=@@@@@@. "
|
||||
echo " *@@@@@@ "
|
||||
echo " :@@@@@= "
|
||||
echo " .@@@@@@. "
|
||||
echo " :@@@@@*. "
|
||||
echo " .=@@@@@- "
|
||||
echo " :+##+. "
|
||||
echo "=============================================================="
|
||||
echo "TTYd session file by iamromulan v1.1"
|
||||
echo "Firmware Revision: $firmware_revision"
|
||||
echo "Serial Number: $serial_number"
|
||||
echo "=============================================================="
|
||||
|
||||
# Start a login session
|
||||
exec /bin/login
|
||||
BIN
Belowx65Toolkit/simpleadmin/htpasswd
Normal file
BIN
Belowx65Toolkit/simpleadmin/htpasswd
Normal file
Binary file not shown.
47
Belowx65Toolkit/simpleadmin/lighttpd.conf
Normal file
47
Belowx65Toolkit/simpleadmin/lighttpd.conf
Normal file
@@ -0,0 +1,47 @@
|
||||
server.modules = (
|
||||
"mod_redirect",
|
||||
"mod_cgi",
|
||||
"mod_proxy",
|
||||
"mod_openssl",
|
||||
"mod_authn_file",
|
||||
)
|
||||
|
||||
server.username = "www-data"
|
||||
server.groupname = "dialout"
|
||||
|
||||
server.port = 80
|
||||
server.document-root = "/usrdata/simpleadmin/www"
|
||||
index-file.names = ( "index.html" )
|
||||
|
||||
auth.backend = "htpasswd"
|
||||
auth.backend.htpasswd.userfile = "/opt/etc/.htpasswd"
|
||||
|
||||
$SERVER["socket"] == "0.0.0.0:443" {
|
||||
ssl.engine = "enable"
|
||||
ssl.privkey= "/usrdata/simpleadmin/server.key"
|
||||
ssl.pemfile= "/usrdata/simpleadmin/server.crt"
|
||||
ssl.acme-tls-1 = "/etc/simpleadmin/dehydrated/tls-alpn-01"
|
||||
ssl.openssl.ssl-conf-cmd = ("MinProtocol" => "TLSv1.2") # (lighttpd 1.4.56 default; recommended to accept only TLSv1.2 and TLSv1.3)
|
||||
auth.require = ( "/" => (
|
||||
"method" => "basic",
|
||||
"realm" => "Authorized users only",
|
||||
"require" => "valid-user"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
# Redirect everything to https
|
||||
$HTTP["scheme"] == "http" {
|
||||
url.redirect = ("" => "https://${url.authority}${url.path}${qsa}")
|
||||
}
|
||||
|
||||
# Anything in /cgi-bin will be run as a script
|
||||
$HTTP["url"] =~ "/cgi-bin/" {
|
||||
cgi.assign = ( "" => "" )
|
||||
}
|
||||
|
||||
# Handle proxy to ttyd if it's running
|
||||
$HTTP["url"] =~ "(^/console)" {
|
||||
proxy.header = ("map-urlpath" => ( "/console" => "/" ), "upgrade" => "enable" )
|
||||
proxy.server = ( "" => ("" => ( "host" => "127.0.0.1", "port" => 8080 )))
|
||||
}
|
||||
60
Belowx65Toolkit/simpleadmin/script/create_watchcat.sh
Normal file
60
Belowx65Toolkit/simpleadmin/script/create_watchcat.sh
Normal file
@@ -0,0 +1,60 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Function to create and run the Watchcat script
|
||||
create_and_run_watchcat_script() {
|
||||
local ip=$1
|
||||
local timeout=$2
|
||||
local failure_count=$3
|
||||
local script_path="/usrdata/simpleadmin/script/watchcat.sh"
|
||||
|
||||
# Create the script with the watchcat logic
|
||||
sudo cat << EOF > $script_path
|
||||
#!/bin/sh
|
||||
|
||||
failures=0
|
||||
|
||||
while :; do
|
||||
if ping -c 1 $ip > /dev/null 2>&1; then
|
||||
failures=0
|
||||
else
|
||||
failures=\$((failures + 1))
|
||||
if [ "\$failures" -ge "$failure_count" ]; then
|
||||
echo "Rebooting system due to \$failures consecutive ping failures."
|
||||
/sbin/reboot
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
sleep $timeout
|
||||
done
|
||||
EOF
|
||||
|
||||
# Make the watchcat script executable
|
||||
chmod +x $script_path
|
||||
|
||||
# Create a JSON to be fetched later
|
||||
echo "{\"enabled\": true, \"track_ip\": \"$ip\", \"ping_timeout\": $timeout, \"ping_failure_count\": $failure_count}" > /usrdata/simpleadmin/script/watchcat.json
|
||||
|
||||
# Check if the script was created successfully
|
||||
if [ -f "$script_path" ]; then
|
||||
# Make the script executable
|
||||
chmod +x "$script_path"
|
||||
|
||||
# Run the script in the background
|
||||
# nohup /bin/sh "$script_path" &
|
||||
/bin/sh "$script_path" &
|
||||
|
||||
echo "Watchcat script created and running."
|
||||
else
|
||||
echo "Failed to create the Watchcat script."
|
||||
echo "Please check the script path: $script_path"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if the script is called with the required parameters
|
||||
if [ "$#" -ne 3 ]; then
|
||||
echo "Usage: $0 <IP> <timeout> <failure_count>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Call the function with the provided arguments
|
||||
create_and_run_watchcat_script "$1" "$2" "$3"
|
||||
32
Belowx65Toolkit/simpleadmin/script/remove_watchcat.sh
Normal file
32
Belowx65Toolkit/simpleadmin/script/remove_watchcat.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Function to remove the Watchcat script and JSON file
|
||||
remove_watchcat_script() {
|
||||
local script_path="/usrdata/simpleadmin/script/watchcat.sh"
|
||||
local json_path="/usrdata/simpleadmin/script/watchcat.json"
|
||||
|
||||
# Mount as read-write
|
||||
mount -o remount,rw /
|
||||
|
||||
# Remove the watchcat script if it exists
|
||||
if [ -f "$script_path" ]; then
|
||||
rm "$script_path"
|
||||
echo "Removed $script_path"
|
||||
else
|
||||
echo "$script_path does not exist"
|
||||
fi
|
||||
|
||||
# Remove the JSON file if it exists
|
||||
if [ -f "$json_path" ]; then
|
||||
rm "$json_path"
|
||||
echo "Removed $json_path"
|
||||
else
|
||||
echo "$json_path does not exist"
|
||||
fi
|
||||
|
||||
# Mount as read-only
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
# Call the function to remove the scripts
|
||||
remove_watchcat_script
|
||||
43
Belowx65Toolkit/simpleadmin/script/ttl_script.sh
Normal file
43
Belowx65Toolkit/simpleadmin/script/ttl_script.sh
Normal file
@@ -0,0 +1,43 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Check if the required parameters are provided
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo "Usage: $0 <enable|disable> <ttl_value>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign the provided parameters to variables
|
||||
mode="$1"
|
||||
ttl_value="$2"
|
||||
|
||||
# Check if iptables is still set
|
||||
ttlcheck=$(/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -vnL | grep TTL | awk '{print $13}')
|
||||
|
||||
# If TTL is still set, manually remove values
|
||||
if [ ! -z "${ttlcheck}" ]; then
|
||||
/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set "${ttlcheck}" &>/dev/null || true
|
||||
/opt/bin/sudo /usr/sbin/ip6tables -w 5 -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set "${ttlcheck}" &>/dev/null || true
|
||||
fi
|
||||
|
||||
# Handle the enable/disable mode
|
||||
case "${mode}" in
|
||||
enable)
|
||||
# Echo TTL to file
|
||||
echo "${ttl_value}" > /usrdata/simplefirewall/ttlvalue
|
||||
|
||||
# Set Start Service
|
||||
/opt/bin/sudo /usrdata/simplefirewall/ttl-override start
|
||||
;;
|
||||
disable)
|
||||
# Remove TTL value file
|
||||
rm -f /usrdata/simplefirewall/ttlvalue
|
||||
|
||||
# Stop the service
|
||||
/opt/bin/sudo /usrdata/simplefirewall/ttl-override stop
|
||||
;;
|
||||
*)
|
||||
echo "Invalid mode: ${mode}"
|
||||
echo "Usage: $0 <enable|disable> <ttl_value>"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
5
Belowx65Toolkit/simpleadmin/simplepasswd
Normal file
5
Belowx65Toolkit/simpleadmin/simplepasswd
Normal file
@@ -0,0 +1,5 @@
|
||||
#/bin/bash
|
||||
|
||||
echo -e "\e[1;31mPlease set your simpleadmin (User: admin) web login password.\e[0m"
|
||||
/usrdata/root/bin/htpasswd -c /opt/etc/.htpasswd admin
|
||||
echo -e "\e[1;32mPassword set.\e[0m"
|
||||
14
Belowx65Toolkit/simpleadmin/systemd/lighttpd.service
Normal file
14
Belowx65Toolkit/simpleadmin/systemd/lighttpd.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Lighttpd Daemon
|
||||
After=network.target opt.mount
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
PIDFile=/opt/var/run/lighttpd.pid
|
||||
ExecStartPre=/opt/sbin/lighttpd -tt -f /usrdata/simpleadmin/lighttpd.conf
|
||||
ExecStart=/opt/sbin/lighttpd -D -f /usrdata/simpleadmin/lighttpd.conf
|
||||
ExecReload=/bin/kill -USR1 $MAINPID
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
12
Belowx65Toolkit/simpleadmin/systemd/ttyd.service
Normal file
12
Belowx65Toolkit/simpleadmin/systemd/ttyd.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=TTYD Service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=/bin/sleep 5
|
||||
ExecStart=/usrdata/simpleadmin/console/ttyd -i 127.0.0.1 -p 8080 -t 'theme={"foreground":"white","background":"black"}' -t fontSize=25 --writable /usrdata/simpleadmin/console/ttyd.bash
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
35
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_atcommand
Normal file
35
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_atcommand
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/bin/bash
|
||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||
function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
|
||||
|
||||
if [ "${QUERY_STRING}" ]; then
|
||||
export IFS="&"
|
||||
for cmd in ${QUERY_STRING}; do
|
||||
if [ "$(echo $cmd | grep '=')" ]; then
|
||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
||||
eval $key=$value
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
x=$(urldecode "$atcmd")
|
||||
MYATCMD=$(printf '%b\n' "${atcmd//%/\\x}")
|
||||
if [ -n "${MYATCMD}" ]; then
|
||||
# Initialize wait time to 200 ms
|
||||
wait_time=200
|
||||
while true; do
|
||||
runcmd=$(echo -en "$x\r\n" | microcom -t $wait_time /dev/ttyOUT2)
|
||||
# Check if "OK" or "ERROR" is present in the response
|
||||
if [[ $runcmd =~ "OK" ]] || [[ $runcmd =~ "ERROR" ]]; then
|
||||
break # Exit the loop if "OK" or "ERROR" is found
|
||||
fi
|
||||
# If neither "OK" nor "ERROR" is found, increment wait time by 1 second
|
||||
((wait_time++))
|
||||
done
|
||||
fi
|
||||
|
||||
echo "Content-type: text/plain"
|
||||
echo $x
|
||||
echo ""
|
||||
echo $runcmd
|
||||
19
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_ping
Normal file
19
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_ping
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script will ping 8.8.8.8 and return the result
|
||||
# If the ping is successful, it will return "OK"
|
||||
# If the ping fails, it will return "ERROR"
|
||||
|
||||
# Send the ping command and store the output
|
||||
ping_output=$(ping -c 1 8.8.8.8)
|
||||
|
||||
# Check if the output contains "0% packet loss"
|
||||
if echo "$ping_output" | grep -q "0% packet loss"; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "OK"
|
||||
else
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "ERROR"
|
||||
fi
|
||||
20
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_ttl_status
Normal file
20
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_ttl_status
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Check iptables for ttlvalue
|
||||
ttlvalue=$(/opt/bin/sudo /usr/sbin/iptables -w 5 -t mangle -vnL | grep TTL | awk '{print $13}' | head -n1)
|
||||
ttlenabled=true;
|
||||
|
||||
# Set Variables
|
||||
if [ -z "${ttlvalue}" ]; then
|
||||
ttlvalue=0
|
||||
ttlenabled=false
|
||||
fi
|
||||
|
||||
echo "Content-type: text/json"
|
||||
echo ""
|
||||
cat <<EOT
|
||||
{
|
||||
"isEnabled": $ttlenabled,
|
||||
"ttl": $ttlvalue
|
||||
}
|
||||
EOT
|
||||
11
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_uptime
Normal file
11
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_uptime
Normal file
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Execute the uptime command and store the result
|
||||
uptime_output=$(uptime)
|
||||
|
||||
# Set header for plain text content
|
||||
echo "Content-Type: text/plain"
|
||||
echo ""
|
||||
|
||||
# Output the uptime result
|
||||
echo "$uptime_output"
|
||||
17
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_watchcat_status
Normal file
17
Belowx65Toolkit/simpleadmin/www/cgi-bin/get_watchcat_status
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Content type header
|
||||
echo "Content-type: application/json"
|
||||
echo ""
|
||||
|
||||
# This script fetches the watchCat parameters from the /tmp/watchcat.json and returns it as JSON
|
||||
# Example content of /tmp/watchcat:
|
||||
# {"watchcat": {"enabled": true, "track_ip": "1.1.1.1", "ping_timeout": 30, "ping_failure_count": 10}}
|
||||
|
||||
# Check if the file exists
|
||||
if [ -f /tmp/watchcat.json ]; then
|
||||
cat /tmp/watchcat.json
|
||||
else
|
||||
# return an empty JSON object
|
||||
echo "{}"
|
||||
fi
|
||||
31
Belowx65Toolkit/simpleadmin/www/cgi-bin/send_sms
Normal file
31
Belowx65Toolkit/simpleadmin/www/cgi-bin/send_sms
Normal file
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||
urldecode() {
|
||||
local data
|
||||
data="${*//+/ }"
|
||||
echo -e "${data//%/\\x}"
|
||||
}
|
||||
|
||||
if [ "${QUERY_STRING}" ]; then
|
||||
export IFS="&"
|
||||
for cmd in ${QUERY_STRING}; do
|
||||
if [[ "$cmd" == *=* ]]; then
|
||||
key=$(echo "$cmd" | awk -F '=' '{print $1}')
|
||||
value=$(echo "$cmd" | awk -F '=' '{print $2}')
|
||||
eval "$key"="$(urldecode "$value")"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
phone_number="$number"
|
||||
message_encoded="$msg"
|
||||
|
||||
|
||||
send_at_command() {
|
||||
local cmd=$1
|
||||
echo -en "$cmd\r" | microcom -t 100 /dev/ttyOUT2
|
||||
}
|
||||
|
||||
send_at_command "AT+CMGS=\"$phone_number\","$Command""
|
||||
runcmd=$((echo -en "$message_encoded"; echo -en "\x1A") | microcom -t 500 /dev/ttyOUT2)
|
||||
echo "$runcmd"
|
||||
64
Belowx65Toolkit/simpleadmin/www/cgi-bin/set_ttl
Normal file
64
Belowx65Toolkit/simpleadmin/www/cgi-bin/set_ttl
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Debug log function
|
||||
log_debug() {
|
||||
local message="$1"
|
||||
debug_logs+=("$message")
|
||||
}
|
||||
|
||||
# Initialize debug logs array
|
||||
declare -a debug_logs=()
|
||||
|
||||
# Get query
|
||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||
if [ "${QUERY_STRING}" ]; then
|
||||
export IFS="&"
|
||||
for cmd in ${QUERY_STRING}; do
|
||||
if [ "$(echo $cmd | grep '=')" ]; then
|
||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
||||
eval $key=$value
|
||||
log_debug "Received parameter: $key=$value"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
setTTL=$(printf '%b\n' "${ttlvalue//%/\\x}")
|
||||
if [ -n "${setTTL}" ]; then
|
||||
log_debug "Stopping service to remove rules"
|
||||
/usrdata/simplefirewall/ttl-override stop
|
||||
|
||||
# Convert ttlvalue to integer
|
||||
if [ "${ttlvalue}" ]; then
|
||||
ttlvalue_int=$(echo "${ttlvalue}" | sed 's/[^0-9]//g')
|
||||
log_debug "Converted ttlvalue to integer: $ttlvalue_int"
|
||||
fi
|
||||
|
||||
# Call the sh script with the appropriate parameters
|
||||
if [ "${ttlvalue_int}" != 0 ]; then
|
||||
log_debug "Enabling TTL with value: ${setTTL}"
|
||||
/usrdata/simpleadmin/script/ttl_script.sh enable "${setTTL}"
|
||||
commandRan="/usrdata/simpleadmin/script/ttl_script.sh enable ${setTTL}"
|
||||
ttlenabled=true
|
||||
ttlvalue=$ttlvalue_int
|
||||
elif [ "${ttlvalue_int}" = 0 ]; then
|
||||
log_debug "Disabling TTL"
|
||||
/usrdata/simpleadmin/script/ttl_script.sh disable 0
|
||||
commandRan="/usrdata/simpleadmin/script/ttl_script.sh disable 0"
|
||||
ttlenabled=false
|
||||
ttlvalue=0
|
||||
fi
|
||||
|
||||
log_debug "Starting service to apply rules"
|
||||
/usrdata/simplefirewall/ttl-override start
|
||||
fi
|
||||
|
||||
echo "Content-type: text/text"
|
||||
echo ""
|
||||
cat <<EOT
|
||||
{
|
||||
"debug_logs": [
|
||||
$(printf '"%s",' "${debug_logs[@]}")
|
||||
]
|
||||
}
|
||||
EOT
|
||||
125
Belowx65Toolkit/simpleadmin/www/cgi-bin/set_watchcat
Normal file
125
Belowx65Toolkit/simpleadmin/www/cgi-bin/set_watchcat
Normal file
@@ -0,0 +1,125 @@
|
||||
#!/bin/bash
|
||||
|
||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||
function urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
|
||||
|
||||
if [ "${QUERY_STRING}" ]; then
|
||||
export IFS="&"
|
||||
for cmd in ${QUERY_STRING}; do
|
||||
if [[ "$cmd" == *"="* ]]; then
|
||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
||||
eval $key=$(urldecode $value)
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ -z "$status" ] || [ -z "$IpDNS" ] || [ -z "$cooldown" ] || [ -z "$failures" ] || [ -z "$action" ]; then
|
||||
response="Missing parameters. Please provide the following parameters: IpDNS, cooldown, failures, action."
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "$response"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$status" == "enabled" ]; then
|
||||
watch_script="/usrdata/simpleadmin/script/watchat.sh"
|
||||
mount -o remount,rw /
|
||||
|
||||
cat <<EOF > $watch_script
|
||||
#!/bin/bash
|
||||
|
||||
ip_or_dns="$IpDNS"
|
||||
cooldown=$cooldown
|
||||
action="$action"
|
||||
fail_count=0
|
||||
max_failures=$failures
|
||||
|
||||
# Process the action variable.
|
||||
|
||||
# Create a JSON file containing the parameters of the script
|
||||
echo -n '{"ip_or_dns":"$ip_or_dns","cooldown":$cooldown,"action":"$action","fail_count":$fail_count,"max_failures":$max_failures}' > /tmp/watchatParams.json
|
||||
|
||||
|
||||
while true; do
|
||||
if ping -c 1 -W 1 \$ip_or_dns > /dev/null; then
|
||||
fail_count=0
|
||||
echo "Success at \$(date)" >> /tmp/watchat.log
|
||||
# Convert /tmp/watchat.log to json format
|
||||
echo -n '{"log":[' > /tmp/watchat.json
|
||||
cat /tmp/watchat.log | sed 's/$/,/' | tr -d '\n' | sed 's/,$//' >> /tmp/watchat.json
|
||||
echo -n ']}' >> /tmp/watchat.json
|
||||
else
|
||||
((fail_count++))
|
||||
if [ \$fail_count -ge \$max_failures ]; then
|
||||
case "\$action" in
|
||||
reboot)
|
||||
echo "Rebooting system..."
|
||||
/sbin/reboot
|
||||
;;
|
||||
switch_sim)
|
||||
echo "Switching SIM..."
|
||||
echo -ne "AT+CNMI=2,1\r" > /dev/ttyOUT2
|
||||
sleep 1
|
||||
echo "Switching SIM at \$(date)" >> /tmp/watchat.log
|
||||
;;
|
||||
none)
|
||||
echo "No action taken."
|
||||
echo "No action taken at \$(date)" >> /tmp/watchat.log
|
||||
;;
|
||||
*)
|
||||
echo "Unknown action: \$action"
|
||||
;;
|
||||
esac
|
||||
# Reset fail count
|
||||
fail_count=0
|
||||
fi
|
||||
fi
|
||||
echo "Fail count: \$fail_count at \$(date)" >> /tmp/watchat.log
|
||||
# Convert /tmp/watchat.log to json format
|
||||
echo -n '{"log":[' > /tmp/watchat.json
|
||||
cat /tmp/watchat.log | sed 's/$/,/' | tr -d '\n' | sed 's/,$//' >> /tmp/watchat.json
|
||||
echo -n ']}' >> /tmp/watchat.json
|
||||
sleep \$cooldown
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x $watch_script
|
||||
|
||||
cat <<EOF > /lib/systemd/system/watchcat.service
|
||||
[Unit]
|
||||
Description=Ping Watcher Service
|
||||
|
||||
[Service]
|
||||
ExecStart=$watch_script
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
ln -s /lib/systemd/system/watchcat.service /etc/systemd/system/multi-user.target.wants/watchcat.service
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl start watchcat.service
|
||||
|
||||
response="Script created at $watch_script and made executable. Service created and started."
|
||||
|
||||
elif [ "$status" == "disabled" ]; then
|
||||
watch_script="/usrdata/simpleadmin/script/watchat.sh"
|
||||
rm -f $watch_script
|
||||
|
||||
systemctl stop watchcat.service
|
||||
rm -f /lib/systemd/system/watchcat.service
|
||||
rm -f /etc/systemd/system/multi-user.target.wants/watchcat.service
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
response="Script removed at $watch_script. Service stopped and removed."
|
||||
else
|
||||
response="Invalid status. Please provide either enabled or disabled."
|
||||
fi
|
||||
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "$response"
|
||||
72
Belowx65Toolkit/simpleadmin/www/cgi-bin/watchcat_maker
Normal file
72
Belowx65Toolkit/simpleadmin/www/cgi-bin/watchcat_maker
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Decode URL-encoded strings
|
||||
function urldecode() {
|
||||
local data=${1//+/ }
|
||||
printf '%b' "${data//%/\\x}"
|
||||
}
|
||||
|
||||
# Parse QUERY_STRING
|
||||
QUERY_STRING=$(echo "${QUERY_STRING}" | sed 's/;//g')
|
||||
if [ "${QUERY_STRING}" ]; then
|
||||
export IFS="&"
|
||||
for cmd in ${QUERY_STRING}; do
|
||||
if [[ "$cmd" == *"="* ]]; then
|
||||
key=$(echo $cmd | awk -F '=' '{print $1}')
|
||||
value=$(echo $cmd | awk -F '=' '{print $2}')
|
||||
eval $key=$(urldecode $value)
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Set default values
|
||||
WATCHCAT_ENABLED=${WATCHCAT_ENABLED:-"disable"}
|
||||
TRACK_IP=${TRACK_IP:-"1.1.1.1"}
|
||||
PING_TIMEOUT=${PING_TIMEOUT:-30}
|
||||
PING_FAILURE_COUNT=${PING_FAILURE_COUNT:-3}
|
||||
|
||||
# Validate input
|
||||
if ! [[ "$WATCHCAT_ENABLED" =~ ^(enable|disable)$ ]]; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "Invalid value for WATCHCAT_ENABLED. Use 'enable' or 'disable'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$TRACK_IP" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "Invalid IP address format for TRACK_IP."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$PING_TIMEOUT" =~ ^[0-9]+$ ]] || [ "$PING_TIMEOUT" -le 0 ]; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "PING_TIMEOUT must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! [[ "$PING_FAILURE_COUNT" =~ ^[0-9]+$ ]] || [ "$PING_FAILURE_COUNT" -le 0 ]; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "PING_FAILURE_COUNT must be a positive integer."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Implement the Watchcat logic
|
||||
if [ "$WATCHCAT_ENABLED" == "enable" ]; then
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "Watchcat is enabled. Tracking IP: $TRACK_IP, Ping timeout: $PING_TIMEOUT seconds, Ping failure count: $PING_FAILURE_COUNT"
|
||||
# Call the create script here and use the needed parameters
|
||||
sudo /usrdata/simpleadmin/script/create_watchcat.sh "$TRACK_IP" "$PING_TIMEOUT" "$PING_FAILURE_COUNT"
|
||||
else
|
||||
echo "Content-type: text/plain"
|
||||
echo ""
|
||||
echo "Watchcat is disabled."
|
||||
# Call the remove script here
|
||||
sudo /usrdata/simpleadmin/script/remove_watchcat.sh
|
||||
fi
|
||||
|
||||
exit 0
|
||||
6
Belowx65Toolkit/simpleadmin/www/css/bootstrap.min.css
vendored
Normal file
6
Belowx65Toolkit/simpleadmin/www/css/bootstrap.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
95
Belowx65Toolkit/simpleadmin/www/css/styles.css
Normal file
95
Belowx65Toolkit/simpleadmin/www/css/styles.css
Normal file
@@ -0,0 +1,95 @@
|
||||
/* import poppins */
|
||||
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap");
|
||||
|
||||
/* import fontawesome icons */
|
||||
@import url("https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css");
|
||||
|
||||
* {
|
||||
font-family: "Poppins", sans-serif;
|
||||
}
|
||||
|
||||
.custom-checkbox .form-check-input {
|
||||
margin-right: 1px;
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loading-modal {
|
||||
background-color: #fff;
|
||||
padding: 3rem;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 18px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border: 3px dotted #000;
|
||||
border-style: solid solid dotted dotted;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
animation: rotation 2s linear infinite;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.loader::after {
|
||||
content: "";
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
border: 3px dotted #0b5ed7;
|
||||
border-style: solid solid dotted;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border-radius: 50%;
|
||||
animation: rotationBack 1s linear infinite;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
@keyframes rotationBack {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.is-warning {
|
||||
background-color: #ffb70f !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.is-medium {
|
||||
font-weight: 600;
|
||||
}
|
||||
522
Belowx65Toolkit/simpleadmin/www/deviceinfo.html
Normal file
522
Belowx65Toolkit/simpleadmin/www/deviceinfo.html
Normal file
@@ -0,0 +1,522 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<!-- <link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||
crossorigin="anonymous"
|
||||
/> -->
|
||||
<!-- Import all the bootstrap css files from css folder -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
|
||||
<!-- Import BootStrap Javascript -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="fetchDeviceInfo()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"
|
||||
><span class="mb-0 h4">Simple Admin</span></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarText"
|
||||
aria-controls="navbarText"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/scanner.html">Simple Scan</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="/deviceinfo.html"
|
||||
aria-current="page"
|
||||
>Device Information</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="row mt-5 gap-3">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Device Information</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Manufacturer</th>
|
||||
<td x-text="manufacturer"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Model Name</th>
|
||||
<td x-text="modelName"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Firmware version</th>
|
||||
<td class="col-md-2" x-text="firmwareVersion"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Phone Number</th>
|
||||
<td class="col-md-2" x-text="phoneNumber"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">IMSI</th>
|
||||
<td class="col-md-2" x-text="imsi"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">ICCID</th>
|
||||
<td class="col-md-2" x-text="iccid"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">IMEI</th>
|
||||
<td class="col-md-2">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
x-model="newImei"
|
||||
x-bind:placeholder="imei === '-' ? 'Fetching IMEI...' : imei"
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="openModal()"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th scope="row">LAN IP</th>
|
||||
<td class="col-md-2" x-text="lanIp"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">WWAN IPv<sup>4</sup></th>
|
||||
<td class="col-md-2" x-text="wwanIpv4"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">WWAN IPv<sup>6</sup></th>
|
||||
<td class="col-md-2" x-text="wwanIpv6"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Simple Admin Version</th>
|
||||
<td class="col-md-2">SimpleAdminRev-Alpha-0.9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Project Contributors</th>
|
||||
<td>
|
||||
<!-- Button trigger modal -->
|
||||
<p
|
||||
type="button"
|
||||
class="link-info link-opacity-50-hover link-offset-2"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#staticBackdrop"
|
||||
>
|
||||
Show Contributors
|
||||
</p>
|
||||
|
||||
<!-- Modal -->
|
||||
<div
|
||||
class="modal fade"
|
||||
id="staticBackdrop"
|
||||
data-bs-backdrop="static"
|
||||
data-bs-keyboard="false"
|
||||
tabindex="-1"
|
||||
aria-labelledby="staticBackdropLabel"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h1
|
||||
class="modal-title fs-5"
|
||||
id="staticBackdropLabel"
|
||||
>
|
||||
Contributors
|
||||
</h1>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
RGMII Toolkit and Documentation
|
||||
</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/iamromulan"
|
||||
target="_blank"
|
||||
>iamromulan</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Simple Admin 2.0</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/dr-dolomite"
|
||||
target="_blank"
|
||||
>dr-dolomite</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>SMS Feature</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/snjzb"
|
||||
target="_blank"
|
||||
>snjzb</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Original Simple Admin</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/aesthernr"
|
||||
target="_blank"
|
||||
>aesthernr</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Original Socat Bridge</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/natecarlson"
|
||||
target="_blank"
|
||||
>natecarlson</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>Original Simple Admin Fixes</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/rbflurry/"
|
||||
target="_blank"
|
||||
>rbflurry</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th>SA Parsing Patch</th>
|
||||
<td class="col-md-2">
|
||||
<a
|
||||
href="https://github.com/tarunVreddy"
|
||||
target="_blank"
|
||||
>tarunVreddy</a
|
||||
>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
Visit our
|
||||
<a
|
||||
href="https://github.com/iamromulan/quectel-rgmii-toolkit/tree/development"
|
||||
target="_blank"
|
||||
class="text-reset"
|
||||
>repository</a
|
||||
>
|
||||
or
|
||||
<a
|
||||
href="https://github.com/iamromulan/quectel-rgmii-configuration-notes.git"
|
||||
target="_blank"
|
||||
class="text-reset"
|
||||
>documentation</a
|
||||
>
|
||||
for more information. All rights reserved. 2024
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Modal for Reboot -->
|
||||
<div class="modal-overlay" x-show="showModal">
|
||||
<div class="loading-modal">
|
||||
<div
|
||||
class="loading-text"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<h3>This will reboot the modem.</h3>
|
||||
<p style="margin-top: 0.5rem">Continue?</p>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-block">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="updateIMEI()"
|
||||
>
|
||||
Reboot
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
@click="closeModal()"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reboot Modal Countdown -->
|
||||
<div class="modal-overlay" x-show="isRebooting">
|
||||
<div class="loading-modal">
|
||||
<div class="loader"></div>
|
||||
<div
|
||||
class="loading-text"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<h3>Rebooting...</h3>
|
||||
<p style="margin-top: 0.5rem">
|
||||
Please wait for
|
||||
<span x-text="countdown" style="font-weight: 500"></span>
|
||||
seconds.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
<script>
|
||||
function fetchDeviceInfo() {
|
||||
return {
|
||||
manufacturer: "-",
|
||||
modelName: "-",
|
||||
firmwareVersion: "-",
|
||||
imsi: "-",
|
||||
iccid: "-",
|
||||
imei: "-",
|
||||
newImei: null,
|
||||
lanIp: "-",
|
||||
wwanIpv4: "-",
|
||||
wwanIpv6: "-",
|
||||
phoneNumber: "Unknown",
|
||||
simpleAdminVersion: "-",
|
||||
atcmd: null,
|
||||
atCommandResponse: "",
|
||||
showModal: false,
|
||||
isLoading: false,
|
||||
isRebooting: false,
|
||||
countdown: 3,
|
||||
|
||||
sendATCommand() {
|
||||
if (!this.atcmd) {
|
||||
// Use ATI as default command
|
||||
console.log(
|
||||
"AT Command is empty, using ATI as default command: "
|
||||
);
|
||||
}
|
||||
|
||||
this.isLoading = true;
|
||||
fetch(
|
||||
"/cgi-bin/get_atcommand?" +
|
||||
new URLSearchParams({
|
||||
atcmd: this.atcmd,
|
||||
})
|
||||
)
|
||||
.then((res) => {
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
this.atCommandResponse = data;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error: ", error);
|
||||
this.showError = true;
|
||||
});
|
||||
},
|
||||
|
||||
fetchATCommand() {
|
||||
this.atcmd =
|
||||
'AT+CGMI;+CGMM;+QGMR;+CIMI;+ICCID;+CGSN;+QMAP="LANIP";+QMAP="WWAN";+CNUM';
|
||||
this.isLoading = true;
|
||||
fetch(
|
||||
"/cgi-bin/get_atcommand?" +
|
||||
new URLSearchParams({
|
||||
atcmd: this.atcmd,
|
||||
})
|
||||
)
|
||||
.then((res) => {
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
this.atCommandResponse = data;
|
||||
this.parseFetchedData();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error: ", error);
|
||||
this.showError = true;
|
||||
});
|
||||
},
|
||||
|
||||
parseFetchedData() {
|
||||
const lines = this.atCommandResponse.split("\n");
|
||||
|
||||
console.log("AT Command Response: ", lines);
|
||||
|
||||
this.manufacturer = lines[1].trim();
|
||||
this.modelName = lines[3].trim();
|
||||
this.firmwareVersion = lines[5].trim();
|
||||
this.imei = lines[11].trim();
|
||||
this.lanIp = lines[13].trim().split(",")[3];
|
||||
this.wwanIpv4 = lines[15].trim().split(",")[4].replace(/"/g, "");
|
||||
this.wwanIpv6 = lines[16].trim().split(",")[4].replace(/"/g, "");
|
||||
|
||||
try {
|
||||
this.imsi = lines[7].trim();
|
||||
this.iccid = lines[9].trim().replace("+ICCID: ", "");
|
||||
this.phoneNumber = lines[18]
|
||||
.trim()
|
||||
.split(",")[1]
|
||||
.replace(/"/g, "");
|
||||
|
||||
if (this.phoneNumber === "") {
|
||||
this.phoneNumber = "Unknown";
|
||||
}
|
||||
} catch (error) {
|
||||
this.phoneNumber = "No SIM Card Inserted or Detected";
|
||||
this.imsi = " ";
|
||||
this.iccid = " ";
|
||||
}
|
||||
|
||||
this.simpleAdminVersion = "SimpleAdminRev-Beta-1.0";
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
updateIMEI() {
|
||||
this.atcmd = `AT+EGMR=1,7,"${this.newImei}"`;
|
||||
this.sendATCommand();
|
||||
this.rebootDevice();
|
||||
},
|
||||
|
||||
rebootDevice() {
|
||||
this.atcmd = "AT+CFUN=1,1";
|
||||
this.sendATCommand();
|
||||
|
||||
this.isLoading = true;
|
||||
this.showModal = false;
|
||||
this.isRebooting = true;
|
||||
this.countdown = 40;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.isLoading = false;
|
||||
this.showModal = false;
|
||||
this.isRebooting = false;
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
openModal() {
|
||||
if (!this.newImei) {
|
||||
alert("No new IMEI provided.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.newImei.length !== 15) {
|
||||
alert("IMEI is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.newImei === this.imei) {
|
||||
alert("IMEI is the same as the current IMEI");
|
||||
return;
|
||||
}
|
||||
|
||||
this.showModal = true;
|
||||
},
|
||||
|
||||
closeModal() {
|
||||
this.showModal = false;
|
||||
},
|
||||
|
||||
init() {
|
||||
this.fetchATCommand();
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
Belowx65Toolkit/simpleadmin/www/favicon.ico
Normal file
BIN
Belowx65Toolkit/simpleadmin/www/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1837
Belowx65Toolkit/simpleadmin/www/index.html
Normal file
1837
Belowx65Toolkit/simpleadmin/www/index.html
Normal file
File diff suppressed because it is too large
Load Diff
5
Belowx65Toolkit/simpleadmin/www/js/alpinejs.min.js
vendored
Normal file
5
Belowx65Toolkit/simpleadmin/www/js/alpinejs.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
Belowx65Toolkit/simpleadmin/www/js/bootstrap.bundle.min.js
vendored
Normal file
7
Belowx65Toolkit/simpleadmin/www/js/bootstrap.bundle.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
37
Belowx65Toolkit/simpleadmin/www/js/dark-mode.js
Normal file
37
Belowx65Toolkit/simpleadmin/www/js/dark-mode.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// Function to toggle dark mode
|
||||
const toggleDarkMode = () => {
|
||||
const html = document.querySelector('html');
|
||||
const currentTheme = html.getAttribute('data-bs-theme');
|
||||
|
||||
if (currentTheme === 'dark') {
|
||||
html.removeAttribute('data-bs-theme');
|
||||
darkModeToggle.textContent = 'Dark Mode';
|
||||
localStorage.setItem('theme', 'light'); // Store the theme in localStorage
|
||||
} else {
|
||||
html.setAttribute('data-bs-theme', 'dark');
|
||||
darkModeToggle.textContent = 'Light Mode';
|
||||
localStorage.setItem('theme', 'dark'); // Store the theme in localStorage
|
||||
}
|
||||
};
|
||||
|
||||
const darkModeToggle = document.getElementById('darkModeToggle');
|
||||
|
||||
// Check if theme preference is stored in localStorage
|
||||
const storedTheme = localStorage.getItem('theme');
|
||||
const html = document.querySelector('html');
|
||||
|
||||
if (storedTheme) {
|
||||
html.setAttribute('data-bs-theme', storedTheme);
|
||||
if (storedTheme === 'dark') {
|
||||
darkModeToggle.textContent = 'Light Mode';
|
||||
} else {
|
||||
darkModeToggle.textContent = 'Dark Mode';
|
||||
}
|
||||
} else {
|
||||
// If no preference is stored, default to dark mode
|
||||
html.setAttribute('data-bs-theme', 'dark');
|
||||
darkModeToggle.textContent = 'Light Mode';
|
||||
localStorage.setItem('theme', 'dark');
|
||||
}
|
||||
|
||||
darkModeToggle.addEventListener('click', toggleDarkMode);
|
||||
37
Belowx65Toolkit/simpleadmin/www/js/generate-freq-box.js
Normal file
37
Belowx65Toolkit/simpleadmin/www/js/generate-freq-box.js
Normal file
@@ -0,0 +1,37 @@
|
||||
const freqNumbersContainer = document.getElementById(
|
||||
"freqNumbersContainer"
|
||||
);
|
||||
|
||||
function generateFreqNumberInputs(num) {
|
||||
let html = "";
|
||||
const maxFields = Math.min(num, 10); // Limit to a maximum of 10 fields
|
||||
for (let i = 1; i <= maxFields; i++) {
|
||||
html += `
|
||||
<div class="input-group mb-3" x-show="cellNum >= ${i} && networkModeCell == 'LTE'">
|
||||
<input
|
||||
type="text"
|
||||
aria-label="EARFCN"
|
||||
placeholder="EARFCN"
|
||||
class="form-control"
|
||||
x-model="earfcn${i}"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
aria-label="PCI"
|
||||
placeholder="PCI"
|
||||
class="form-control"
|
||||
x-model="pci${i}"
|
||||
/>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const cellNumInput = document.querySelector("[aria-label='NumCells']");
|
||||
cellNumInput.addEventListener("input", function () {
|
||||
const cellNum = parseInt(this.value);
|
||||
freqNumbersContainer.innerHTML = generateFreqNumberInputs(cellNum);
|
||||
});
|
||||
});
|
||||
60
Belowx65Toolkit/simpleadmin/www/js/parse-settings.js
Normal file
60
Belowx65Toolkit/simpleadmin/www/js/parse-settings.js
Normal file
@@ -0,0 +1,60 @@
|
||||
function parseCurrentSettings(rawdata) {
|
||||
const data = rawdata;
|
||||
|
||||
const lines = data.split("\n");
|
||||
console.log(lines);
|
||||
|
||||
// Remove QUIMSLOT and only take 1 or 2
|
||||
this.sim = lines[1].split(":")[1].trim();
|
||||
this.apn = lines[3].split(",")[2].replace(/\"/g, "");
|
||||
this.cellLock4GStatus = lines[5].split(",")[1].replace(/\"/g, "");
|
||||
this.cellLock5GStatus = lines[7].split(",")[1].replace(/\"/g, "");
|
||||
this.prefNetwork = lines[9].split(",")[1].replace(/\"/g, "");
|
||||
this.nrModeControlStatus = lines[11].split(",")[1].replace(/\"/g, "");
|
||||
|
||||
|
||||
let bands = [];
|
||||
|
||||
// Append the values if there is separated by comma with a space.
|
||||
// i.e. LTE BAND 3, LTE BAND 1
|
||||
for (let i = 13; i < 17; i++) {
|
||||
if (lines[i].split(",").length > 1) {
|
||||
bands.push(lines[i].split(",")[3].replace(/\"/g, " "));
|
||||
}
|
||||
}
|
||||
|
||||
this.bands = bands;
|
||||
|
||||
|
||||
if (this.cellLock4GStatus == 1 && this.cellLock5GStatus == 1) {
|
||||
this.cellLockStatus = "Locked to 4G and 5G";
|
||||
} else if (this.cellLock4GStatus == 1) {
|
||||
this.cellLockStatus = "Locked to 4G";
|
||||
}
|
||||
else if (this.cellLock5GStatus == 1) {
|
||||
this.cellLockStatus = "Locked to 5G";
|
||||
}
|
||||
else {
|
||||
this.cellLockStatus = "Not Locked";
|
||||
}
|
||||
|
||||
if (this.nrModeControlStatus == 0) {
|
||||
this.nrModeControlStatus = "Not Disabled";
|
||||
}
|
||||
else if (this.nrModeControlStatus == 1) {
|
||||
this.nrModeControlStatus = "SA Disabled";
|
||||
}
|
||||
else {
|
||||
this.nrModeControlStatus = "NSA Disabled";
|
||||
}
|
||||
|
||||
return {
|
||||
sim: sim,
|
||||
apn: apn,
|
||||
cellLockStatus: cellLockStatus,
|
||||
prefNetwork: prefNetwork,
|
||||
nrModeControl: nrModeControlStatus,
|
||||
bands: bands
|
||||
};
|
||||
}
|
||||
|
||||
76
Belowx65Toolkit/simpleadmin/www/js/populate-checkbox.js
Normal file
76
Belowx65Toolkit/simpleadmin/www/js/populate-checkbox.js
Normal file
@@ -0,0 +1,76 @@
|
||||
function populateCheckboxes(lte_band, nsa_nr5g_band, nr5g_band, locked_lte_bands, locked_nsa_bands, locked_sa_bands, cellLock) {
|
||||
var checkboxesForm = document.getElementById("checkboxForm");
|
||||
var selectedMode = document.getElementById("networkModeBand").value;
|
||||
var bands;
|
||||
|
||||
// Determine bands based on selected network mode
|
||||
if (selectedMode === "LTE") {
|
||||
bands = lte_band;
|
||||
} else if (selectedMode === "NSA") {
|
||||
bands = nsa_nr5g_band;
|
||||
} else if (selectedMode === "SA") {
|
||||
bands = nr5g_band;
|
||||
}
|
||||
|
||||
checkboxesForm.innerHTML = ""; // Clear existing checkboxes
|
||||
|
||||
var bandsArray;
|
||||
if (bands !== null) {
|
||||
bandsArray = bands.split(":");
|
||||
bandsArray.forEach(function(band, index) {
|
||||
if (index % 5 === 0) {
|
||||
currentRow = document.createElement("div");
|
||||
currentRow.className = "row mb-2 mx-auto"; // Add margin bottom for spacing
|
||||
checkboxesForm.appendChild(currentRow);
|
||||
}
|
||||
|
||||
var checkboxDiv = document.createElement("div");
|
||||
checkboxDiv.className = "form-check form-check-reverse col-2"; // Each checkbox takes a column
|
||||
var checkboxInput = document.createElement("input");
|
||||
checkboxInput.className = "form-check-input";
|
||||
checkboxInput.type = "checkbox";
|
||||
checkboxInput.id = "inlineCheckbox" + band;
|
||||
checkboxInput.value = band;
|
||||
checkboxInput.autocomplete = "off";
|
||||
|
||||
// Store the locked bands in an array
|
||||
var locked_lte_bands_array = locked_lte_bands.split(":");
|
||||
var locked_nsa_bands_array = locked_nsa_bands.split(":");
|
||||
var locked_sa_bands_array = locked_sa_bands.split(":");
|
||||
|
||||
// Check if the current band is locked
|
||||
var isLocked = false;
|
||||
if (selectedMode === "LTE") {
|
||||
if (locked_lte_bands_array.includes(band)) {
|
||||
isLocked = true;
|
||||
}
|
||||
} else if (selectedMode === "NSA") {
|
||||
if (locked_nsa_bands_array.includes(band)) {
|
||||
isLocked = true;
|
||||
}
|
||||
} else if (selectedMode === "SA") {
|
||||
if (locked_sa_bands_array.includes(band)) {
|
||||
isLocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isLocked) {
|
||||
checkboxInput.checked = true;
|
||||
}
|
||||
|
||||
var checkboxLabel = document.createElement("label");
|
||||
checkboxLabel.className = "form-check-label";
|
||||
checkboxLabel.htmlFor = "inlineCheckbox" + band;
|
||||
checkboxLabel.innerText = "B" + band;
|
||||
|
||||
checkboxDiv.appendChild(checkboxInput);
|
||||
checkboxDiv.appendChild(checkboxLabel);
|
||||
currentRow.appendChild(checkboxDiv);
|
||||
});
|
||||
} else {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
var currentRow;
|
||||
addCheckboxListeners(cellLock);
|
||||
}
|
||||
932
Belowx65Toolkit/simpleadmin/www/network.html
Normal file
932
Belowx65Toolkit/simpleadmin/www/network.html
Normal file
@@ -0,0 +1,932 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<!-- <link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||
crossorigin="anonymous"
|
||||
/> -->
|
||||
<!-- Import all the bootstrap css files from css folder -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
|
||||
<!-- Logo -->
|
||||
<link rel="simpleadmin-logo" href="favicon.ico" />
|
||||
|
||||
<!-- Import BootStrap Javascript -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="cellLocking()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"
|
||||
><span class="mb-0 h4">Simple Admin</span></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarText"
|
||||
aria-controls="navbarText"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="network.html"
|
||||
aria-current="page"
|
||||
>Simple Network</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/scanner.html">Simple Scan</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="deviceinfo.html"
|
||||
>Device Information</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="row mt-5 gap-3">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row align-items-center">
|
||||
<div class="col">Band Locking</div>
|
||||
<div class="col-md-3">
|
||||
<select
|
||||
class="form-select"
|
||||
id="networkModeBand"
|
||||
aria-label="LTE"
|
||||
>
|
||||
<option selected value="LTE">LTE</option>
|
||||
<option value="NSA">NR5G-NSA</option>
|
||||
<option value="SA">NR5G-SA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<h5 class="card-subtitle" x-show="isGettingBands === true">
|
||||
Fetching supported bands...
|
||||
</h5>
|
||||
<form id="checkboxForm" x-show="isGettingBands === false">
|
||||
<!-- Checkboxes will be populated here -->
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="col">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary m-2"
|
||||
@click="lockSelectedBands()"
|
||||
>
|
||||
Lock Bands
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-info m-2"
|
||||
id="uncheckAll"
|
||||
>
|
||||
Uncheck All
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger m-2"
|
||||
@click="resetBandLocking()"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<p x-text="'Active bands: ' + bands"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row gap-3 mt-4">
|
||||
<div class="col">
|
||||
<form>
|
||||
<div class="card">
|
||||
<div class="card-header">Network Utilities</div>
|
||||
<div class="card-body row">
|
||||
<div class="col">
|
||||
<div class="mb-4">
|
||||
<label for="APN" class="form-label">APN</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="APN"
|
||||
x-model="newApn"
|
||||
aria-describedby="APN"
|
||||
x-bind:placeholder="apn === '-' ? 'Fetching...' : apn"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- <div class="mb-4">
|
||||
<label for="disableCA" class="form-label"
|
||||
>Disable Carrier Aggregation</label
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
id="disableCA"
|
||||
x-model="disableCA"
|
||||
aria-label="disableCA"
|
||||
>
|
||||
<option
|
||||
selected
|
||||
x-text="disableCA === '-' ? 'Fetching...' : 'Current: ' + disableCA"
|
||||
></option>
|
||||
<option value="enableAll">Enable All</option>
|
||||
<option value="LTE">Disable LTE</option>
|
||||
<option value="NR5G">Disable NR5G</option>
|
||||
<option value="both">Disable Both</option>
|
||||
</select>
|
||||
</div> -->
|
||||
|
||||
<div class="mb-4 input-group grid gap-3">
|
||||
<label for="SIM1" class="form-label"> Change SIM</label>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="inlineRadioOptions"
|
||||
aria-describedby="SIM1"
|
||||
id="SIM1"
|
||||
value="option1"
|
||||
x-bind:checked="sim === '1'"
|
||||
x-on:click="newSim = '1'"
|
||||
/>
|
||||
<label class="form-check-label" for="inlineRadio1"
|
||||
>1</label
|
||||
>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="radio"
|
||||
name="inlineRadioOptions"
|
||||
aria-describedby="SIM2"
|
||||
id="SIM2"
|
||||
value="option2"
|
||||
x-bind:checked="sim === '2'"
|
||||
x-on:click="newSim = '2'"
|
||||
/>
|
||||
<label class="form-check-label" for="inlineRadio2"
|
||||
>2</label
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="mb-4">
|
||||
<label for="nrModeControl" class="form-label"
|
||||
>Select Preferred Network</label
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
id="prefNetworkMode"
|
||||
x-model="prefNetworkMode"
|
||||
aria-label="prefNetworkMode"
|
||||
>
|
||||
<option
|
||||
selected
|
||||
x-text="prefNetwork === '-' ? 'Fetching...' : 'Current: ' + prefNetwork"
|
||||
></option>
|
||||
<option value="AUTO">AUTO</option>
|
||||
<option value="LTE">LTE Only</option>
|
||||
<option value="LTE:NR5G">NR5G-NSA</option>
|
||||
<option value="NR5G">NR5G-SA</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-4">
|
||||
<label for="prefNetwork" class="form-label"
|
||||
>NR5G Mode Control</label
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
id="nrModeControl"
|
||||
x-model="nrModeControl"
|
||||
aria-label="nrModeControl"
|
||||
>
|
||||
<option
|
||||
selected
|
||||
x-text="nrModeControl === '-' ? 'Fetching...' : 'Current: ' + nrModeControl"
|
||||
></option>
|
||||
<option value="0">Enable All</option>
|
||||
<option value="2">Disable NR5G-NSA</option>
|
||||
<option value="1">Disable NR5G-SA</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
@click="saveChanges()"
|
||||
>
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<div class="card">
|
||||
<div class="card-header">Cell Locking</div>
|
||||
<div class="card-body">
|
||||
<select
|
||||
class="form-select"
|
||||
id="networkModeCell"
|
||||
x-model="networkModeCell"
|
||||
aria-label="LTE"
|
||||
>
|
||||
<option
|
||||
selected
|
||||
x-text="'Cell Lock: ' + cellLockStatus"
|
||||
></option>
|
||||
<option>LTE</option>
|
||||
<option>NR5G-SA</option>
|
||||
<option>Unlock LTE</option>
|
||||
<option>Unlock NR5G-SA</option>
|
||||
</select>
|
||||
|
||||
<div class="my-4">
|
||||
<!-- For LTE -->
|
||||
<div id="lteElementsCell" x-show="networkModeCell == 'LTE'">
|
||||
<div class="input-group mb-3">
|
||||
<span class="input-group-text" id="basic-addon1"
|
||||
>Num Cells</span
|
||||
>
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
placeholder="1-10"
|
||||
min="1"
|
||||
max="10"
|
||||
aria-label="NumCells"
|
||||
aria-describedby="basic-addon1"
|
||||
x-model="cellNum"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="freqNumbersContainer">
|
||||
<!-- Generate EARFCN and PCI here -->
|
||||
</div>
|
||||
|
||||
<!-- For SA -->
|
||||
<div
|
||||
id="saElementsCell"
|
||||
x-show="networkModeCell == 'NR5G-SA'"
|
||||
>
|
||||
<div
|
||||
class="input-group mb-3"
|
||||
x-show="networkModeCell == 'NR5G-SA'"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
aria-label="EARFCN"
|
||||
placeholder="EARFCN"
|
||||
class="form-control"
|
||||
x-model="earfcn1"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
aria-label="PCI"
|
||||
placeholder="PCI"
|
||||
class="form-control"
|
||||
x-model="pci1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="input-group mb-3"
|
||||
x-show="networkModeCell == 'NR5G-SA'"
|
||||
>
|
||||
<select
|
||||
class="form-select"
|
||||
x-model="scs"
|
||||
aria-label="SCS"
|
||||
>
|
||||
<option selected>SCS</option>
|
||||
<option>15</option>
|
||||
<option>30</option>
|
||||
<option>60</option>
|
||||
<option>120</option>
|
||||
<option>240</option>
|
||||
</select>
|
||||
<input
|
||||
type="text"
|
||||
aria-label="band"
|
||||
placeholder="Band"
|
||||
class="form-control"
|
||||
x-model="band"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
x-show="networkModeCell == 'LTE'"
|
||||
@click="cellLockEnableLTE()"
|
||||
>
|
||||
Lock LTE Cells
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-primary"
|
||||
x-show="networkModeCell == 'NR5G-SA'"
|
||||
@click="cellLockEnableNR()"
|
||||
>
|
||||
Lock NR5G-SA Cells
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
x-show="networkModeCell == 'Unlock LTE'"
|
||||
@click="cellLockDisableLTE()"
|
||||
>
|
||||
Unlock LTE Cells
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-danger"
|
||||
x-show="networkModeCell == 'Unlock NR5G-SA'"
|
||||
@click="cellLockDisableNR()"
|
||||
>
|
||||
Unlock NR5G-SA Cells
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
Cell Locking only works for the primary cell and is not
|
||||
persistent across reboots.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Loading Modal for Locking Band -->
|
||||
<div class="modal-overlay" x-show="showModal">
|
||||
<div class="loading-modal">
|
||||
<div class="loader"></div>
|
||||
<div
|
||||
class="loading-text"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<h3>Initializing Network...</h3>
|
||||
<p style="margin-top: 0.5rem">
|
||||
Please wait for
|
||||
<span x-text="countdown" style="font-weight: 500"></span>
|
||||
seconds.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Import Band Locking GUI JS -->
|
||||
<!-- <script src="js/band-locking.js"></script> -->
|
||||
<script src="js/generate-freq-box.js"></script>
|
||||
<script src="js/populate-checkbox.js"></script>
|
||||
<script src="js/parse-settings.js"></script>
|
||||
<script>
|
||||
function cellLocking() {
|
||||
return {
|
||||
isLoading: false,
|
||||
showModal: false,
|
||||
countdown: 0,
|
||||
networkModeCell: "-",
|
||||
earfcn1: null,
|
||||
pci1: null,
|
||||
earfcn2: null,
|
||||
pci2: null,
|
||||
earfcn3: null,
|
||||
pci3: null,
|
||||
earfcn4: null,
|
||||
pci4: null,
|
||||
earfcn5: null,
|
||||
pci5: null,
|
||||
earfcn6: null,
|
||||
pci6: null,
|
||||
earfcn7: null,
|
||||
pci7: null,
|
||||
earfcn8: null,
|
||||
pci8: null,
|
||||
earfcn9: null,
|
||||
pci9: null,
|
||||
earfcn10: null,
|
||||
pci10: null,
|
||||
scs: null,
|
||||
band: null,
|
||||
apn: "-",
|
||||
newApn: null,
|
||||
prefNetwork: "-",
|
||||
prefNetworkMode: null,
|
||||
nrModeControl: "-",
|
||||
cellNum: null,
|
||||
lte_bands: null,
|
||||
nsa_bands: null,
|
||||
sa_bands: null,
|
||||
locked_lte_bands: null,
|
||||
locked_nsa_bands: null,
|
||||
locked_sa_bands: null,
|
||||
currentNetworkMode: "-",
|
||||
updatedLockedBands: null,
|
||||
sim: "-",
|
||||
newSim: null,
|
||||
cellLockStatus: "Unknown",
|
||||
bands: "Fetching Bands...",
|
||||
isGettingBands: false,
|
||||
rawdata: null,
|
||||
|
||||
getSupportedBands() {
|
||||
const atcmd = 'AT+QNWPREFCFG="policy_band"';
|
||||
this.sendATcommand(atcmd)
|
||||
.then((rawdata) => {
|
||||
this.rawdata = rawdata;
|
||||
this.parseSupportedBands(rawdata);
|
||||
})
|
||||
.then(() => {
|
||||
this.getLockedBands();
|
||||
});
|
||||
},
|
||||
|
||||
parseSupportedBands(rawdata) {
|
||||
const data = rawdata;
|
||||
const regex = /"([^"]+)",([0-9:]+)/g;
|
||||
|
||||
// Object to store the results
|
||||
const bands = {};
|
||||
|
||||
let match;
|
||||
while ((match = regex.exec(data)) !== null) {
|
||||
const bandType = match[1];
|
||||
const numbers = match[2].split(":").map(Number);
|
||||
bands[bandType] = numbers;
|
||||
}
|
||||
|
||||
// Seperate the bands for each network mode
|
||||
this.lte_bands = bands.lte_band.join(":");
|
||||
this.nsa_bands = bands.nsa_nr5g_band.join(":");
|
||||
this.sa_bands = bands.nr5g_band.join(":");
|
||||
},
|
||||
|
||||
getLockedBands() {
|
||||
const atcmd =
|
||||
'AT+QNWPREFCFG="lte_band";+QNWPREFCFG= "nsa_nr5g_band";+QNWPREFCFG= "nr5g_band"';
|
||||
|
||||
this.sendATcommand(atcmd)
|
||||
.then((rawdata) => {
|
||||
this.rawdata = rawdata;
|
||||
this.parseLockedBands(rawdata);
|
||||
})
|
||||
.then(() => {
|
||||
// Call current settings
|
||||
this.getCurrentSettings();
|
||||
});
|
||||
},
|
||||
|
||||
parseLockedBands(rawdata) {
|
||||
const data = rawdata;
|
||||
const regex = /"([^"]+)",([0-9:]+)/g;
|
||||
|
||||
// Object to store the results
|
||||
const bands = {};
|
||||
|
||||
let match;
|
||||
while ((match = regex.exec(data)) !== null) {
|
||||
const bandType = match[1];
|
||||
const numbers = match[2].split(":").map(Number);
|
||||
bands[bandType] = numbers;
|
||||
}
|
||||
|
||||
// Seperate the bands for each network mode
|
||||
this.locked_lte_bands = bands.lte_band.join(":");
|
||||
this.locked_nsa_bands = bands.nsa_nr5g_band.join(":");
|
||||
this.locked_sa_bands = bands.nr5g_band.join(":");
|
||||
|
||||
populateCheckboxes(
|
||||
this.lte_bands,
|
||||
this.nsa_bands,
|
||||
this.sa_bands,
|
||||
this.locked_lte_bands,
|
||||
this.locked_nsa_bands,
|
||||
this.locked_sa_bands,
|
||||
this
|
||||
);
|
||||
},
|
||||
|
||||
init() {
|
||||
// Function to populate checkboxes
|
||||
const showPopulateCheckboxes = () => {
|
||||
this.isGettingBands = true;
|
||||
this.getSupportedBands();
|
||||
this.isGettingBands = false;
|
||||
|
||||
// Add event listeners to checkboxes after populating them
|
||||
addCheckboxListeners(this);
|
||||
};
|
||||
|
||||
// Function to track checkbox changes
|
||||
this.trackCheckboxChanges = () => {
|
||||
var selectedMode =
|
||||
document.getElementById("networkModeBand").value;
|
||||
var checkboxes = document.querySelectorAll(
|
||||
'input[type="checkbox"]'
|
||||
);
|
||||
var newCheckedValues = [];
|
||||
|
||||
checkboxes.forEach(function (checkbox) {
|
||||
if (checkbox.checked) {
|
||||
newCheckedValues.push(checkbox.value);
|
||||
}
|
||||
});
|
||||
|
||||
// Update currentNetworkMode and updatedLockedBands
|
||||
this.currentNetworkMode = selectedMode;
|
||||
this.updatedLockedBands = newCheckedValues;
|
||||
};
|
||||
|
||||
// Function to add event listener to network mode dropdown
|
||||
const addNetworkModeListener = () => {
|
||||
document
|
||||
.getElementById("networkModeBand")
|
||||
.addEventListener("change", function () {
|
||||
showPopulateCheckboxes(); // Update checkboxes when network mode changes
|
||||
});
|
||||
};
|
||||
|
||||
// Execute necessary functions on initialization
|
||||
showPopulateCheckboxes();
|
||||
addNetworkModeListener();
|
||||
},
|
||||
getCurrentSettings() {
|
||||
const atcmd =
|
||||
'AT+QUIMSLOT?;+CGCONTRDP=1;+QNWLOCK="common/4g";+QNWLOCK="common/5g";+QNWPREFCFG="mode_pref";+QNWPREFCFG="nr5g_disable_mode";+QCAINFO';
|
||||
|
||||
this.sendATcommand(atcmd).then((rawdata) => {
|
||||
const settings = parseCurrentSettings(rawdata);
|
||||
this.sim = settings.sim;
|
||||
this.apn = settings.apn;
|
||||
this.cellLockStatus = settings.cellLockStatus;
|
||||
this.prefNetwork = settings.prefNetwork;
|
||||
this.nrModeControl = settings.nrModeControl;
|
||||
this.bands = settings.bands;
|
||||
});
|
||||
},
|
||||
lockSelectedBands() {
|
||||
// Get the updated this.currentNetworkMode = selectedMode; and this.updatedLockedBands = newCheckedValues;
|
||||
const selectedMode = this.currentNetworkMode;
|
||||
const newCheckedValues = this.updatedLockedBands;
|
||||
let atcmd;
|
||||
|
||||
// Check if both values are null then show the error message
|
||||
if (selectedMode === null || newCheckedValues === null) {
|
||||
} else {
|
||||
if (selectedMode === "LTE") {
|
||||
atcmd = `AT+QNWPREFCFG="lte_band",${newCheckedValues.join(
|
||||
":"
|
||||
)}`;
|
||||
console.log(atcmd);
|
||||
this.sendATcommand(atcmd);
|
||||
} else if (selectedMode === "NSA") {
|
||||
atcmd = `AT+QNWPREFCFG="nsa_nr5g_band",${newCheckedValues.join(
|
||||
":"
|
||||
)}`;
|
||||
console.log(atcmd);
|
||||
this.sendATcommand(atcmd);
|
||||
} else if (selectedMode === "SA") {
|
||||
atcmd = `AT+QNWPREFCFG="nr5g_band",${newCheckedValues.join(
|
||||
":"
|
||||
)}`;
|
||||
console.log(atcmd);
|
||||
this.sendATcommand(atcmd);
|
||||
} else {
|
||||
alert("Invalid network mode selected");
|
||||
}
|
||||
|
||||
// Do a 2 second countdown
|
||||
this.showModal = true;
|
||||
this.countdown = 2;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
|
||||
// Refresh the page to show the updated bands
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
resetBandLocking() {
|
||||
// Send the atcmd command to reset the locked bands
|
||||
const atcmd = 'AT+QNWPREFCFG="restore_band"';
|
||||
|
||||
this.showModal = true;
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
|
||||
this.countdown = 5;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
|
||||
// Refresh the page to show the updated bands
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Run init function to repopulate the checkboxes
|
||||
this.init();
|
||||
},
|
||||
saveChanges() {
|
||||
const newApn = this.newApn;
|
||||
const newSim = this.newSim;
|
||||
const prefNetworkMode = this.prefNetworkMode;
|
||||
const nrModeControl = this.nrModeControl;
|
||||
|
||||
let atAPN, atSIM, ATNetwork, ATNRMode, atcmd;
|
||||
atAPN = "";
|
||||
atSIM = "";
|
||||
ATNetwork = "";
|
||||
ATNRMode = "";
|
||||
|
||||
if (newApn !== null) {
|
||||
atAPN = `+CGDCONT=1,"IP","${newApn}";`;
|
||||
}
|
||||
|
||||
if (newSim !== null) {
|
||||
atSIM = `+QUIMSLOT=${newSim};`;
|
||||
}
|
||||
|
||||
if (prefNetworkMode !== null) {
|
||||
ATNetwork = `+QNWPREFCFG="mode_pref",${prefNetworkMode};`;
|
||||
}
|
||||
|
||||
if (nrModeControl !== this.nrModeControl) {
|
||||
ATNRMode = `+QNWPREFCFG="nr5g_disable_mode",${nrModeControl}`;
|
||||
}
|
||||
|
||||
atcmd = `AT+${atAPN}${atSIM}${ATNetwork}${ATNRMode}`;
|
||||
// If there is double + (++), remove 1 + from the command
|
||||
atcmd = atcmd.replace("++", "+");
|
||||
if (atcmd !== "AT+") {
|
||||
this.showModal = true;
|
||||
console.log(atcmd);
|
||||
|
||||
// If atcmd has QUIMSLOT, do a reboot instead
|
||||
if (atcmd.includes("QUIMSLOT")) {
|
||||
atcmd = atcmd + "+CFUN=1,1";
|
||||
this.sendATcommand(atcmd);
|
||||
this.countdown = 45;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
// Do a 15 second countdown
|
||||
this.countdown = 15;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
alert("No changes made");
|
||||
}
|
||||
},
|
||||
cellLockEnableLTE() {
|
||||
const cellNum = this.cellNum;
|
||||
|
||||
if (cellNum === null) {
|
||||
alert("Please enter the number of cells to lock");
|
||||
return; // Exit the function early if cellNum is null
|
||||
}
|
||||
|
||||
// Create an array to hold earfcn and pci pairs
|
||||
const earfcnPciPairs = [
|
||||
{ earfcn: this.earfcn1, pci: this.pci1 },
|
||||
{ earfcn: this.earfcn2, pci: this.pci2 },
|
||||
{ earfcn: this.earfcn3, pci: this.pci3 },
|
||||
{ earfcn: this.earfcn4, pci: this.pci4 },
|
||||
{ earfcn: this.earfcn5, pci: this.pci5 },
|
||||
{ earfcn: this.earfcn6, pci: this.pci6 },
|
||||
{ earfcn: this.earfcn7, pci: this.pci7 },
|
||||
{ earfcn: this.earfcn8, pci: this.pci8 },
|
||||
{ earfcn: this.earfcn9, pci: this.pci9 },
|
||||
{ earfcn: this.earfcn10, pci: this.pci10 },
|
||||
];
|
||||
|
||||
// Filter out pairs where either earfcn or pci is null
|
||||
const validPairs = earfcnPciPairs.filter(
|
||||
(pair) => pair.earfcn !== null && pair.pci !== null
|
||||
);
|
||||
|
||||
if (validPairs.length === 0) {
|
||||
alert("Please enter at least one valid earfcn and pci pair");
|
||||
return; // Exit the function early if no valid pairs are found
|
||||
}
|
||||
|
||||
// Construct the AT command using the valid pairs
|
||||
let atcmd = `AT+QNWLOCK="common/4g",${cellNum},${validPairs
|
||||
.map((pair) => `${pair.earfcn},${pair.pci}`)
|
||||
.join(",")}`;
|
||||
|
||||
// Mock data
|
||||
this.showModal = true;
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
|
||||
// Do a 15 second countdown
|
||||
this.countdown = 15;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
cellLockEnableNR() {
|
||||
const earfcn = this.earfcn1;
|
||||
const pci = this.pci1;
|
||||
const scs = this.scs;
|
||||
const band = this.band;
|
||||
|
||||
if (
|
||||
earfcn === null ||
|
||||
pci === null ||
|
||||
scs === null ||
|
||||
band === null
|
||||
) {
|
||||
alert("Please enter all the required fields");
|
||||
return; // Exit the function early if any of the fields are null
|
||||
}
|
||||
|
||||
// Construct the AT command using the valid pairs
|
||||
let atcmd = `AT+QNWLOCK="common/5g",${earfcn},${pci},${scs},${band}`;
|
||||
|
||||
// Mock data
|
||||
this.showModal = true;
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
|
||||
// Do a 15 second countdown
|
||||
this.countdown = 15;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
cellLockDisableLTE() {
|
||||
// Send the atcmd command to reset the locked bands
|
||||
const atcmd = 'AT+QNWLOCK="common/4g",0';
|
||||
this.showModal = true;
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
|
||||
this.countdown = 15;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
cellLockDisableNR() {
|
||||
// Send the atcmd command to reset the locked bands
|
||||
const atcmd = 'AT+QNWLOCK="common/5g,0"';
|
||||
|
||||
this.showModal = true;
|
||||
|
||||
this.sendATcommand(atcmd);
|
||||
|
||||
this.countdown = 15;
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.showModal = false;
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
sendATcommand(atcmd) {
|
||||
return fetch(
|
||||
"/cgi-bin/get_atcommand?" +
|
||||
new URLSearchParams({
|
||||
atcmd: atcmd,
|
||||
})
|
||||
)
|
||||
.then((response) => response.text())
|
||||
.then((data) => {
|
||||
return data;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
// Throw the error again to ensure it's propagated
|
||||
throw error;
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function addCheckboxListeners(cellLock) {
|
||||
// Remove existing event listeners
|
||||
document
|
||||
.querySelectorAll('input[type="checkbox"]')
|
||||
.forEach(function (checkbox) {
|
||||
checkbox.removeEventListener(
|
||||
"change",
|
||||
cellLock.trackCheckboxChanges
|
||||
);
|
||||
});
|
||||
|
||||
// Add new event listeners
|
||||
document
|
||||
.querySelectorAll('input[type="checkbox"]')
|
||||
.forEach(function (checkbox) {
|
||||
checkbox.addEventListener("change", cellLock.trackCheckboxChanges);
|
||||
});
|
||||
}
|
||||
|
||||
// Function for unchecking all checkboxes
|
||||
document
|
||||
.getElementById("uncheckAll")
|
||||
.addEventListener("click", function () {
|
||||
document
|
||||
.querySelectorAll('input[type="checkbox"]')
|
||||
.forEach(function (checkbox) {
|
||||
checkbox.checked = false;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
2393
Belowx65Toolkit/simpleadmin/www/scanner.html
Normal file
2393
Belowx65Toolkit/simpleadmin/www/scanner.html
Normal file
File diff suppressed because it is too large
Load Diff
643
Belowx65Toolkit/simpleadmin/www/settings.html
Normal file
643
Belowx65Toolkit/simpleadmin/www/settings.html
Normal file
@@ -0,0 +1,643 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
|
||||
<!-- Logo -->
|
||||
<link rel="simpleadmin-logo" href="favicon.ico" />
|
||||
|
||||
<!-- Import BootStrap Javascript -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="simpleSettings()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"
|
||||
><span class="mb-0 h4">Simple Admin</span></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarText"
|
||||
aria-controls="navbarText"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/scanner.html">Simple Scan</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="/settings.html"
|
||||
aria-current="page"
|
||||
>Simple Settings</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/deviceinfo.html"
|
||||
>Device Information</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="row mt-5 mb-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">AT Terminal</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="form-floating mb-4">
|
||||
<!-- At commands output here -->
|
||||
<textarea
|
||||
class="form-control"
|
||||
placeholder="ATI"
|
||||
id="atOutputBox"
|
||||
style="height: 210px"
|
||||
x-text="atCommandResponse"
|
||||
readonly
|
||||
>
|
||||
<label for="floatingTextarea">ATI</label>
|
||||
</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<div class="col-md-4 mb-3">
|
||||
<label for="exampleInputEmail1" class="form-label"
|
||||
>AT Command</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="atCommandInput"
|
||||
placeholder="ATI"
|
||||
aria-describedby="atCommandInput"
|
||||
x-model="atcmd"
|
||||
@keydown.enter="sendATCommand()"
|
||||
/>
|
||||
<div id="atCommandInputHelper" class="form-text">
|
||||
Seperate multiple commands with comma (,).
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="d-grid gap-2 d-md-flex justify-content-md-start"
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary me-md-2"
|
||||
type="button"
|
||||
@click="sendATCommand()"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
@click="clearResponses()"
|
||||
:disabled="isClean"
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">One Click Utilities</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">Reboot</th>
|
||||
<td>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger"
|
||||
@click="showRebootModal()"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Reboot
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Reset AT Commands Settings</th>
|
||||
<td>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger"
|
||||
@click="resetATCommands()"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Reset
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">IP Passthrough</th>
|
||||
<td>
|
||||
<select
|
||||
class="form-select"
|
||||
id="ipPassModeSelect"
|
||||
x-model="ipPassMode"
|
||||
>
|
||||
<option selected>Passthrough Mode</option>
|
||||
<option value="ETH">ETH</option>
|
||||
<option value="USB">USB (ECM/RNDIS)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
@click="ipPassThroughEnable()"
|
||||
x-show="ipPassStatus === false"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Enable
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger"
|
||||
@click="ipPassThroughDisable()"
|
||||
x-show="ipPassStatus === true"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Disable
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">USB Modem Protocol</th>
|
||||
<td>
|
||||
<select
|
||||
class="form-select"
|
||||
id="usbNetModeSelect"
|
||||
x-model="usbNetMode"
|
||||
>
|
||||
<option
|
||||
selected
|
||||
x-text="currentUsbNetMode"
|
||||
></option>
|
||||
<option value="RMNET">RMNET</option>
|
||||
<option value="ECM">ECM (Recommended)</option>
|
||||
<option value="MBIM">MBIM</option>
|
||||
<option value="RNDIS">RNDIS</option>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
@click="usbNetModeChanger()"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Change
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Onboard DNS Proxy</th>
|
||||
<td>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary"
|
||||
@click="onBoardDNSProxyEnable()"
|
||||
x-show="DNSProxyStatus === false"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Enable
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger"
|
||||
@click="onBoardDNSProxyDisable()"
|
||||
x-show="DNSProxyStatus === true"
|
||||
:disabled="isLoading"
|
||||
>
|
||||
Disable
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="card mb-3">
|
||||
<div class="card-header">TTL and Network Scan Settings</div>
|
||||
<div class="card-body">
|
||||
<label for="TTLState" class="form-label"
|
||||
>TTL State and Value</label
|
||||
>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div
|
||||
class="p-3 text-primary-emphasis bg-primary-subtle border border-primary-subtle rounded-3"
|
||||
x-show="ttlStatus === true"
|
||||
>
|
||||
TTL is Active
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="p-3 text-danger-emphasis bg-danger-subtle border border-danger-subtle rounded-3"
|
||||
x-show="ttlStatus === false"
|
||||
>
|
||||
TTL is Inactive
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div
|
||||
class="p-3 text-info-emphasis bg-info-subtle border border-info-subtle rounded-3 mb-4"
|
||||
x-text="ttlvalue"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-text mb-3">
|
||||
<div class="mb-4">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="ttlInput"
|
||||
placeholder="TTL Value"
|
||||
x-model="newTTL"
|
||||
/>
|
||||
<div id="ttlValueHelper" class="form-text">
|
||||
Set TTL Value to 0 to disable.
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-grid gap-1">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="setTTL()"
|
||||
>
|
||||
Update
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="card-text">
|
||||
<div class="d-flex flex-row gap-4 w-full">
|
||||
<p><a class="link-info link-opacity-50-hover link-offset-2" href="/scanner.html">Go to Cell Scanner</a></p>
|
||||
<p><a class="link-info link-opacity-50-hover link-offset-2" href="/watchcat.html">Go to WatchCat</a></p>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Modal for Reboot -->
|
||||
<div class="modal-overlay" x-show="showModal">
|
||||
<div class="loading-modal">
|
||||
<div
|
||||
class="loading-text"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<h3>This will reboot the modem.</h3>
|
||||
<p style="margin-top: 0.5rem">Continue?</p>
|
||||
</div>
|
||||
<div class="d-grid gap-2 d-md-block">
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
type="button"
|
||||
@click="rebootDevice()"
|
||||
>
|
||||
Reboot
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-danger"
|
||||
type="button"
|
||||
@click="closeModal()"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reboot Modal Countdown -->
|
||||
<div class="modal-overlay" x-show="isRebooting">
|
||||
<div class="loading-modal">
|
||||
<div class="loader"></div>
|
||||
<div
|
||||
class="loading-text"
|
||||
style="display: flex; flex-direction: column"
|
||||
>
|
||||
<h3>Rebooting...</h3>
|
||||
<p style="margin-top: 0.5rem">
|
||||
Please wait for
|
||||
<span x-text="countdown" style="font-weight: 500"></span>
|
||||
seconds.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
<script>
|
||||
function simpleSettings() {
|
||||
return {
|
||||
isLoading: false,
|
||||
showSuccess: false,
|
||||
showError: false,
|
||||
isClean: true,
|
||||
showModal: false,
|
||||
isRebooting: false,
|
||||
atcmd: "",
|
||||
fetchATCommand: "",
|
||||
countdown: 0,
|
||||
atCommandResponse: "",
|
||||
currentSettingsResponse: "",
|
||||
ttldata: null,
|
||||
ttlvalue: 0,
|
||||
ttlStatus: false,
|
||||
newTTL: null,
|
||||
ipPassMode: "Unspecified",
|
||||
ipPassStatus: false,
|
||||
usbNetMode: "Unspecified",
|
||||
currentUsbNetMode: "Unknown",
|
||||
DNSProxyStatus: true,
|
||||
|
||||
closeModal() {
|
||||
this.confirmModal = false;
|
||||
this.showModal = false;
|
||||
},
|
||||
|
||||
showRebootModal() {
|
||||
this.showModal = true;
|
||||
},
|
||||
|
||||
sendATCommand() {
|
||||
if (!this.atcmd) {
|
||||
// Use ATI as default command
|
||||
this.atcmd = "ATI";
|
||||
console.log(
|
||||
"AT Command is empty, using ATI as default command: ",
|
||||
this.atcmd
|
||||
);
|
||||
}
|
||||
this.isLoading = true;
|
||||
const encodedATCmd = encodeURIComponent(this.atcmd);
|
||||
const url = `/cgi-bin/get_atcommand?atcmd=${encodedATCmd}`;
|
||||
|
||||
fetch(url)
|
||||
.then((res) => {
|
||||
if (!res.ok) {
|
||||
throw new Error(`HTTP error! status: ${res.status}`);
|
||||
}
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
this.atCommandResponse = data;
|
||||
this.isLoading = false;
|
||||
this.isClean = false;
|
||||
this.fetchCurrentSettings();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error: ", error);
|
||||
this.showError = true;
|
||||
this.isLoading = false;
|
||||
});
|
||||
},
|
||||
|
||||
clearResponses() {
|
||||
this.atCommandResponse = "";
|
||||
this.isClean = true;
|
||||
},
|
||||
|
||||
rebootDevice() {
|
||||
this.atcmd = "AT+CFUN=1,1";
|
||||
this.sendATCommand();
|
||||
|
||||
this.atCommandResponse = "";
|
||||
this.showModal = false;
|
||||
this.isRebooting = true;
|
||||
this.countdown = 40;
|
||||
|
||||
// Do the countdown
|
||||
const interval = setInterval(() => {
|
||||
this.countdown--;
|
||||
if (this.countdown === 0) {
|
||||
clearInterval(interval);
|
||||
this.isRebooting = false;
|
||||
this.init();
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
resetATCommands() {
|
||||
this.atcmd = "AT&F";
|
||||
this.sendATCommand();
|
||||
console.log("Resetting AT Commands");
|
||||
this.atcmd = "";
|
||||
this.atCommandResponse = "";
|
||||
this.showRebootModal();
|
||||
},
|
||||
|
||||
ipPassThroughEnable() {
|
||||
if (this.ipPassMode != "Unspecified") {
|
||||
if (this.ipPassMode == "ETH") {
|
||||
this.atcmd =
|
||||
// at+qmap="mpdn_rule",0,1,1,1,1,"FF:FF:FF:FF:FF:FF"
|
||||
'AT+QMAP="MPDN_RULE",0,1,0,1,1,"FF:FF:FF:FF:FF:FF"';
|
||||
this.sendATCommand();
|
||||
} else if (this.ipPassMode == "USB") {
|
||||
this.atcmd =
|
||||
'AT+QMAP="MPDN_RULE",0,1,0,3,1,"FF:FF:FF:FF:FF:FF"';
|
||||
this.sendATCommand();
|
||||
} else {
|
||||
console.error("Invalid IP Passthrough Mode");
|
||||
}
|
||||
} else {
|
||||
console.error("IP Passthrough Mode not specified");
|
||||
}
|
||||
},
|
||||
|
||||
ipPassThroughDisable() {
|
||||
this.atcmd = 'AT+QMAP="MPDN_RULE",0;+QMAPWAC=1';
|
||||
this.sendATCommand();
|
||||
},
|
||||
|
||||
onBoardDNSProxyEnable() {
|
||||
this.atcmd = 'AT+QMAP="DHCPV4DNS","enable"';
|
||||
this.sendATCommand().then(() => {
|
||||
this.fetchCurrentSettings();
|
||||
});
|
||||
},
|
||||
|
||||
onBoardDNSProxyDisable() {
|
||||
this.atcmd = 'AT+QMAP="DHCPV4DNS","disable"';
|
||||
this.sendATCommand().then(() => {
|
||||
this.fetchCurrentSettings();
|
||||
});
|
||||
},
|
||||
|
||||
usbNetModeChanger() {
|
||||
if (this.usbNetMode != "Unspecified") {
|
||||
if (this.usbNetMode == "RMNET") {
|
||||
this.atcmd = 'AT+QCFG="usbnet",0;';
|
||||
this.sendATCommand();
|
||||
} else if (this.usbNetMode == "ECM") {
|
||||
this.atcmd = 'AT+QCFG="usbnet",1;';
|
||||
this.sendATCommand();
|
||||
} else if (this.usbNetMode == "MBIM") {
|
||||
this.atcmd = 'AT+QCFG="usbnet",2;';
|
||||
this.sendATCommand();
|
||||
} else if (this.usbNetMode == "RNDIS") {
|
||||
this.atcmd = 'AT+QCFG="usbnet",3;';
|
||||
this.sendATCommand();
|
||||
} else {
|
||||
console.log("USB Net Mode Invalid");
|
||||
}
|
||||
} else {
|
||||
console.error("USB Net Mode not specified");
|
||||
}
|
||||
this.rebootDevice();
|
||||
},
|
||||
|
||||
fetchCurrentSettings() {
|
||||
this.fetchATCommand =
|
||||
'AT+QMAP="MPDN_RULE";+QMAP="DHCPV4DNS";+QCFG="usbnet"';
|
||||
fetch(
|
||||
"/cgi-bin/get_atcommand?" +
|
||||
new URLSearchParams({
|
||||
atcmd: this.fetchATCommand,
|
||||
})
|
||||
)
|
||||
.then((res) => {
|
||||
return res.text();
|
||||
})
|
||||
.then((data) => {
|
||||
// Set the value of currentSettingsResponse
|
||||
this.currentSettingsResponse = data;
|
||||
const currentData = data.split("\n");
|
||||
console.log("Lines: ", currentData);
|
||||
|
||||
const testEthpass = currentData[1].match(
|
||||
/\+QMAP: "MPDN_rule",0,0,0,0,0/
|
||||
);
|
||||
|
||||
if (testEthpass) {
|
||||
this.ipPassStatus = false;
|
||||
} else {
|
||||
this.ipPassStatus = true;
|
||||
}
|
||||
|
||||
const testDNSProxy = currentData[6].match(
|
||||
/\+QMAP: "DHCPV4DNS","enable"/
|
||||
);
|
||||
|
||||
if (testDNSProxy) {
|
||||
this.DNSProxyStatus = true;
|
||||
} else {
|
||||
this.DNSProxyStatus = false;
|
||||
}
|
||||
|
||||
const testUSBNet = currentData[8].match(
|
||||
/\+QCFG: "usbnet",(\d)/
|
||||
);
|
||||
|
||||
if (testUSBNet[1] == "0") {
|
||||
this.currentUsbNetMode = "RMNET";
|
||||
} else if (testUSBNet[1] == "1") {
|
||||
this.currentUsbNetMode = "ECM";
|
||||
} else if (testUSBNet[1] == "2") {
|
||||
this.currentUsbNetMode = "MBIM";
|
||||
} else if (testUSBNet[1] == "3") {
|
||||
this.currentUsbNetMode = "RNDIS";
|
||||
} else {
|
||||
this.currentUsbNetMode = "Unknown";
|
||||
}
|
||||
|
||||
// clear atcmd
|
||||
this.atcmd = "";
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error: ", error);
|
||||
this.showError = true;
|
||||
});
|
||||
},
|
||||
|
||||
fetchTTL() {
|
||||
fetch("/cgi-bin/get_ttl_status")
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
this.ttldata = data;
|
||||
this.ttlStatus = this.ttldata.isEnabled;
|
||||
this.ttlvalue = this.ttldata.ttl;
|
||||
});
|
||||
},
|
||||
|
||||
setTTL() {
|
||||
this.isLoading = true; // Set loading state while updating TTL
|
||||
const ttlval = this.newTTL;
|
||||
fetch(
|
||||
"/cgi-bin/set_ttl?" + new URLSearchParams({ ttlvalue: ttlval })
|
||||
)
|
||||
.then((res) => res.text()) // Use res.text() instead of res.json()
|
||||
.then((data) => {
|
||||
// Manually handle the response data
|
||||
console.log("Response from server:", data);
|
||||
// You can try to parse the JSON manually or handle the response as needed
|
||||
|
||||
// Once TTL is updated, fetch the updated TTL data
|
||||
this.fetchTTL();
|
||||
this.isLoading = false; // Set loading state back to false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error updating TTL: ", error);
|
||||
this.isLoading = false; // Ensure loading state is properly handled in case of error
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.fetchCurrentSettings();
|
||||
this.fetchTTL();
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
418
Belowx65Toolkit/simpleadmin/www/sms.html
Normal file
418
Belowx65Toolkit/simpleadmin/www/sms.html
Normal file
@@ -0,0 +1,418 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="dark">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<!-- 导入自定义和Bootstrap样式 -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
<!-- 网站图标 -->
|
||||
<link rel="icon" href="favicon.ico" />
|
||||
<!-- 导入Bootstrap和Alpine.js脚本 -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
|
||||
<!-- Contributed By: snjzb -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="fetchSMS()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"><span class="mb-0 h4">Simple Admin</span></a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarText"
|
||||
aria-controls="navbarText" aria-expanded="false" aria-label="切换导航">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 ml-4 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/scanner.html">Simple Scan</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/settings.html">Simple Settings</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" aria-current="page" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/deviceinfo.html">Device Information</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row mt-5 mb-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">SMS Inbox</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="col">
|
||||
<div style="
|
||||
max-height: 400px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
">
|
||||
<div x-show="isLoading">
|
||||
<h4>Fetching SMS...</h4>
|
||||
</div>
|
||||
<table class="table table-hover border-success" x-show="!isLoading">
|
||||
<tbody>
|
||||
<!-- 没有消息时显示 -->
|
||||
<!-- Display when there are no messages -->
|
||||
<template x-if="messages.length === 0 && !isLoading">
|
||||
<div>
|
||||
<p>Inbox is Empty</p>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 循环显示短信消息 -->
|
||||
<!-- "Loop display SMS messages" -->
|
||||
<template x-for="(message, index) in messages" :key="index">
|
||||
<tr>
|
||||
<td>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" :value="index"
|
||||
x-model="selectedMessages" />
|
||||
<div class="row column-gap-1 mb-2">
|
||||
<div class="col-md-3">
|
||||
<p x-text="'Sender: ' + senders[index]"></p>
|
||||
</div>
|
||||
<div class="col">
|
||||
<p x-text="'Date and Time: ' + dates[index]"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-9">
|
||||
<p x-text="message.text"></p>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加判断,只有当messages数组有内容时才显示全选复选框及其区域 -->
|
||||
<!-- Add a judgment, only when the messages array has content will the select all checkbox and its area be displayed" -->
|
||||
<div class="card-body border-top" x-show="messages.length > 0">
|
||||
<div class="form-check">
|
||||
<input id="selectAllCheckbox" class="form-check-input" type="checkbox" @change="toggleAll($event)" />
|
||||
<label class="form-check-label">Select All</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="d-grid gap-2 d-md-flex justify-content-md-start">
|
||||
<!-- 刷新按钮 -->
|
||||
<!-- Refresh button -->
|
||||
<button class="btn btn-success" type="button" @click="init()">
|
||||
Refresh
|
||||
</button>
|
||||
<!-- 删除选中短信按钮 -->
|
||||
<!-- Delete selected SMS button -->
|
||||
<button class="btn btn-danger" type="button" @click="deleteSelectedSMS()">
|
||||
Delete Selected SMS
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-5 mb-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Send Message</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="phoneNumber" class="form-label">Recipient's Number</label>
|
||||
<input type="text" class="form-control" id="phoneNumber" x-model="phoneNumber"
|
||||
placeholder="Enter the recipient's number." />
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="messageToSend" class="form-label">SMS Content</label>
|
||||
<textarea class="form-control" id="messageToSend" rows="3" x-model="messageToSend"
|
||||
placeholder="Enter SMS content."></textarea>
|
||||
</div>
|
||||
<div id="notification" class="alert" style="display: none;"></div>
|
||||
<button class="btn btn-primary" @click="sendSMS()">
|
||||
Send SMS
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
<script>
|
||||
function fetchSMS() {
|
||||
return {
|
||||
isLoading: false,
|
||||
atCommandResponse: "",
|
||||
messages: [],
|
||||
senders: [],
|
||||
dates: [],
|
||||
selectedMessages: [],
|
||||
phoneNumber: '',
|
||||
messageToSend: '',
|
||||
messageIndices: [], // 确保初始化messageIndices数组
|
||||
|
||||
// 清除现有数据
|
||||
clearData() {
|
||||
this.messages = [];
|
||||
this.senders = [];
|
||||
this.dates = [];
|
||||
this.selectedMessages = [];
|
||||
this.messageIndices = [];
|
||||
const selectAllCheckbox = document.getElementById('selectAllCheckbox');
|
||||
if (selectAllCheckbox) {
|
||||
selectAllCheckbox.checked = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 请求获取短信
|
||||
requestSMS() {
|
||||
this.isLoading = true;
|
||||
fetch(`/cgi-bin/get_atcommand?${new URLSearchParams({ atcmd: "AT+CSMS=1;+CSDH=0;+CNMI=2,1,0,0,0;+CMGF=1;+CSCA?;+CSMP=17,167,0,8;+CPMS=\"ME\",\"ME\",\"ME\";+CSCS=\"UCS2\";+CMGL=\"ALL\"" })}`)
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
this.atCommandResponse = data.split('\n')
|
||||
.filter(line => line.trim() !== "OK" && line.trim() !== "")
|
||||
.join('\n');
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false;
|
||||
this.clearData();
|
||||
this.parseSMSData(this.atCommandResponse);
|
||||
});
|
||||
},
|
||||
|
||||
// 解析短信数据的方法
|
||||
parseSMSData(data) {
|
||||
const cmglRegex = /^\s*\+CMGL:\s*(\d+),"[^"]*","([^"]*)"[^"]*,"([^"]*)"/gm;
|
||||
const cscaRegex = /^\s*\+CSCA:\s*"([^"]*)"/gm;
|
||||
this.messageIndices = [];
|
||||
this.serviceCenters = [];
|
||||
this.dates = [];
|
||||
this.senders = [];
|
||||
this.messages = [];
|
||||
let match;
|
||||
let lastIndex = null;
|
||||
while ((match = cmglRegex.exec(data)) !== null) {
|
||||
const index = parseInt(match[1]);
|
||||
const senderHex = match[2];
|
||||
const sender = senderHex.startsWith("003") ? this.convertHexToText(senderHex) : senderHex;
|
||||
const dateStr = match[3].replace(/\+\d{2}$/, "");
|
||||
const date = this.parseCustomDate(dateStr);
|
||||
if (isNaN(date)) {
|
||||
console.error(`Invalid Date: ${dateStr}`);
|
||||
continue;
|
||||
}
|
||||
const startIndex = cmglRegex.lastIndex;
|
||||
const endIndex = data.indexOf("+CMGL:", startIndex) !== -1 ? data.indexOf("+CMGL:", startIndex) : data.length;
|
||||
const messageHex = data.substring(startIndex, endIndex).trim();
|
||||
const message = /^[0-9a-fA-F]+$/.test(messageHex) ? this.convertHexToText(messageHex) : messageHex;
|
||||
if (lastIndex !== null && this.messages[lastIndex].sender === sender && (date - this.messages[lastIndex].date) / 1000 <= 1) {
|
||||
this.messages[lastIndex].text += " " + message;
|
||||
this.messages[lastIndex].indices.push(index);
|
||||
this.dates[lastIndex] = this.formatDate(date);
|
||||
} else {
|
||||
this.messageIndices.push([index]);
|
||||
this.senders.push(sender);
|
||||
this.dates.push(this.formatDate(date));
|
||||
this.messages.push({ text: message, sender: sender, date: date, indices: [index] });
|
||||
lastIndex = this.messages.length - 1;
|
||||
}
|
||||
}
|
||||
while ((match = cscaRegex.exec(data)) !== null) {
|
||||
const serviceCenterHex = match[1];
|
||||
const serviceCenter = this.convertHexToText(serviceCenterHex);
|
||||
this.serviceCenters.push(serviceCenter);
|
||||
}
|
||||
},
|
||||
|
||||
// 将十六进制转换为文本(假设使用 UTF-16BE 编码)
|
||||
convertHexToText(hex) {
|
||||
const bytes = new Uint8Array(hex.match(/.{1,2}/g).map(byte => parseInt(byte, 16)));
|
||||
return new TextDecoder('utf-16be').decode(bytes);
|
||||
},
|
||||
|
||||
// 自定义解析日期函数
|
||||
parseCustomDate(dateStr) {
|
||||
const [datePart, timePart] = dateStr.split(',');
|
||||
const [day, month, year] = datePart.split('/').map(part => parseInt(part, 10));
|
||||
const [hour, minute, second] = timePart.split(':').map(part => parseInt(part, 10));
|
||||
|
||||
// 将日期转换为标准格式的日期对象
|
||||
return new Date(Date.UTC(2000 + year, month - 1, day, hour, minute, second));
|
||||
},
|
||||
|
||||
// 自定义格式化日期函数
|
||||
formatDate(date) {
|
||||
const year = date.getUTCFullYear() - 2000;
|
||||
const month = (date.getUTCMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getUTCDate().toString().padStart(2, '0');
|
||||
const hour = date.getUTCHours().toString().padStart(2, '0');
|
||||
const minute = date.getUTCMinutes().toString().padStart(2, '0');
|
||||
const second = date.getUTCSeconds().toString().padStart(2, '0');
|
||||
return `${day}/${month}/${year},${hour}:${minute}:${second}`;
|
||||
},
|
||||
|
||||
// 删除选中的短信
|
||||
deleteSelectedSMS() {
|
||||
if (this.selectedMessages.length === 0) {
|
||||
console.warn("没有选中的短信");
|
||||
return;
|
||||
}
|
||||
if (!this.messageIndices || this.messageIndices.length === 0) {
|
||||
console.error("短信索引未正确初始化或为空");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否全选
|
||||
const isAllSelected = this.selectedMessages.length === this.messages.length;
|
||||
|
||||
if (isAllSelected) {
|
||||
// 如果全选,则调用删除所有短信的方法
|
||||
this.deleteAllSMS();
|
||||
} else {
|
||||
// 否则,删除选中的短信
|
||||
const indicesToDelete = [];
|
||||
this.selectedMessages.forEach(index => {
|
||||
indicesToDelete.push(...this.messages[index].indices);
|
||||
});
|
||||
if (indicesToDelete.length === 0) {
|
||||
console.warn("没有有效的短信索引");
|
||||
return;
|
||||
}
|
||||
|
||||
// 拼接 AT 命令
|
||||
const atCommands = indicesToDelete.map((index, i) => i === 0 ? `AT+CMGD=${index}` : `+CMGD=${index}`).join(';');
|
||||
fetch(`/cgi-bin/get_atcommand?${new URLSearchParams({ atcmd: atCommands })}`)
|
||||
.finally(() => {
|
||||
this.selectedMessages = [];
|
||||
this.requestSMS();
|
||||
});
|
||||
}
|
||||
},
|
||||
// 删除所有短信
|
||||
deleteAllSMS() {
|
||||
fetch(`/cgi-bin/get_atcommand?${new URLSearchParams({ atcmd: "AT+CMGD=,4" })}`)
|
||||
.finally(() => {
|
||||
this.init();
|
||||
});
|
||||
},
|
||||
// 发送短信
|
||||
encodeUCS2(input) {
|
||||
let output = '';
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
const hex = input.charCodeAt(i).toString(16).toUpperCase().padStart(4, '0');
|
||||
output += hex;
|
||||
}
|
||||
return output;
|
||||
},
|
||||
|
||||
async sendSMS() {
|
||||
let phoneNumberWithCountryCode;
|
||||
if (this.phoneNumber.length < 11) {
|
||||
phoneNumberWithCountryCode = this.phoneNumber;
|
||||
} else {
|
||||
const serviceCenterPrefix = this.serviceCenters[0].substring(0, 3);
|
||||
phoneNumberWithCountryCode = `${serviceCenterPrefix}${this.phoneNumber}`;
|
||||
}
|
||||
const encodedPhoneNumber = this.encodeUCS2(phoneNumberWithCountryCode);
|
||||
const messageSegments = this.splitMessage(this.messageToSend, 70); // 将消息分段
|
||||
const uid = Math.floor(Math.random() * 256); // 生成随机的UID
|
||||
const totalSegments = messageSegments.length;
|
||||
let allSegmentsSent = true;
|
||||
let errorCode = null;
|
||||
for (let i = 0; i < totalSegments; i++) {
|
||||
const segment = messageSegments[i];
|
||||
const encodedMessage = this.encodeUCS2(segment);
|
||||
const currentSegment = i + 1;
|
||||
const Command = `${uid},${currentSegment},${totalSegments}`;
|
||||
const params = new URLSearchParams({
|
||||
number: encodedPhoneNumber,
|
||||
msg: encodedMessage,
|
||||
Command: Command
|
||||
});
|
||||
try {
|
||||
const response = await fetch(`/cgi-bin/send_sms?${params.toString()}`);
|
||||
const data = await response.text();
|
||||
console.log("Response from server:", data);
|
||||
|
||||
// 检查返回的数据中是否包含 '+CMS ERROR'
|
||||
if (data.includes('+CMS ERROR')) {
|
||||
errorCode = data.match(/\+CMS ERROR: (\d+)/)?.[1];
|
||||
console.error("SMS send error:", data);
|
||||
allSegmentsSent = false;
|
||||
break; // 停止发送剩余的段
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fetch error:", error);
|
||||
allSegmentsSent = false;
|
||||
break; // 停止发送剩余的段
|
||||
}
|
||||
}
|
||||
if (allSegmentsSent) {
|
||||
this.showNotification("SMS sent successfully!");
|
||||
} else {
|
||||
this.showNotification(`SMS sending failed!: ${errorCode}`);
|
||||
}
|
||||
},
|
||||
|
||||
splitMessage(message, length) {
|
||||
const segments = [];
|
||||
for (let i = 0; i < message.length; i += length) {
|
||||
segments.push(message.substring(i, i + length));
|
||||
}
|
||||
return segments;
|
||||
},
|
||||
|
||||
showNotification(message, type) {
|
||||
const notification = document.getElementById('notification');
|
||||
notification.innerText = message;
|
||||
notification.className = `alert alert-${type}`;
|
||||
notification.style.display = 'block';
|
||||
setTimeout(() => {
|
||||
notification.style.display = 'none';
|
||||
}, 3000); // 3秒后自动关闭
|
||||
},
|
||||
|
||||
// 初始化
|
||||
// Initialize
|
||||
init() {
|
||||
this.clearData();
|
||||
this.requestSMS();
|
||||
},
|
||||
|
||||
// 全选/取消全选
|
||||
// Select all/deselect all
|
||||
toggleAll(event) {
|
||||
this.selectedMessages = event.target.checked ? this.messages.map((_, index) => index) : [];
|
||||
}
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
275
Belowx65Toolkit/simpleadmin/www/watchcat.html
Normal file
275
Belowx65Toolkit/simpleadmin/www/watchcat.html
Normal file
@@ -0,0 +1,275 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<!-- Import all the bootstrap css files from css folder -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
|
||||
<!-- Logo -->
|
||||
<link rel="simpleadmin-logo" href="favicon.ico" />
|
||||
|
||||
<!-- Import BootStrap Javascript -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
|
||||
<style>
|
||||
.form-switch .form-check-input {
|
||||
width: 2.4em;
|
||||
height: 1.2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="simpleWatchCat()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"
|
||||
><span class="mb-0 h4">Simple Admin</span></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarText"
|
||||
aria-controls="navbarText"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 ml-4 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/scanner.html">Simple Scan</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="/settings.html"
|
||||
aria-current="page"
|
||||
>Simple Settings</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/deviceinfo.html"
|
||||
>Device Information</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row mt-3 mb-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Simple Watchcat</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="row mt-3 mb-5 align-content-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3">
|
||||
<label> Enable Watchcat </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="mt-2">
|
||||
<div class="form-check form-switch form-switch-lg">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="watchCatSwitch"
|
||||
x-model="watchCatStatus"
|
||||
:disabled="!isFormComplete"
|
||||
x-on:change="setWatchCatSettings"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3 mb-3 align-items-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Track IP </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Ping Request Timeout </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Ping Failure Amount </label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-5">
|
||||
<div class="mt-3 mb-4">
|
||||
<select
|
||||
class="form-select"
|
||||
aria-label="Select Site to Ping"
|
||||
x-model="trackIP"
|
||||
>
|
||||
<option selected>Select IP</option>
|
||||
<option value="1.1.1.1">1.1.1.1</option>
|
||||
<option value="8.8.8.8">8.8.8.8</option>
|
||||
<option value="9.9.9.9">9.9.9.9</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="Ping Timeout"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Enter Ping Timeout in Seconds."
|
||||
x-model="pingTimeout"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="Sizing example input"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Enter Ping Failure Amount."
|
||||
x-model="pingFailureCount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
Still under development. Coming soon...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3 mb-3">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Simple Watchcat Logs</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="form-floating">
|
||||
<textarea
|
||||
class="form-control"
|
||||
placeholder="Leave a comment here"
|
||||
id="floatingTextarea2"
|
||||
style="height: 100px"
|
||||
x-text="response"
|
||||
readonly
|
||||
></textarea>
|
||||
<label for="floatingTextarea2">Logs</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
No log is provided when successfully enabling the watchcat.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
<script>
|
||||
function simpleWatchCat() {
|
||||
return {
|
||||
watchCatStatus: false, // Initialize as false (not enabled)
|
||||
trackIP: "",
|
||||
pingTimeout: "",
|
||||
pingFailureCount: "",
|
||||
response: "",
|
||||
|
||||
setWatchCatSettings() {
|
||||
fetch(
|
||||
"/cgi-bin/watchcat_maker?" +
|
||||
new URLSearchParams({
|
||||
WATCHCAT_ENABLED: this.watchCatStatus ? "enable" : "disable",
|
||||
TRACK_IP: this.trackIP,
|
||||
PING_TIMEOUT: this.pingTimeout,
|
||||
PING_FAILURE_COUNT: this.pingFailureCount,
|
||||
})
|
||||
)
|
||||
.then((response) => response.text()) // Convert response to text
|
||||
.then((data) => {
|
||||
this.response = data; // Store the response data
|
||||
console.log(data); // Log the response for debugging
|
||||
})
|
||||
.then(() => {
|
||||
this.fetchWatchCatSettings();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error); // Handle any errors
|
||||
this.response = "An error occurred.";
|
||||
});
|
||||
},
|
||||
|
||||
// Computed property to check if the form is complete
|
||||
get isFormComplete() {
|
||||
return (
|
||||
this.trackIP !== "" &&
|
||||
this.pingTimeout !== "" &&
|
||||
this.pingFailureCount !== ""
|
||||
);
|
||||
},
|
||||
|
||||
// Fetch the current watchcat settings
|
||||
fetchWatchCatSettings() {
|
||||
fetch("/cgi-bin/get_watchcat_status")
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
return response.json(); // Parse response as JSON
|
||||
})
|
||||
.then((data) => {
|
||||
console.log(data); // Log the parsed data for debugging
|
||||
|
||||
// Check if the JSON is not empty
|
||||
if (data) {
|
||||
this.watchCatStatus = data.enabled === true;
|
||||
this.trackIP = data.track_ip;
|
||||
this.pingTimeout = data.ping_timeout;
|
||||
this.pingFailureCount = data.ping_failure_count;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error); // Handle any errors
|
||||
this.response = "An error occurred.";
|
||||
});
|
||||
},
|
||||
|
||||
init() {
|
||||
this.fetchWatchCatSettings();
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
351
Belowx65Toolkit/simpleadmin/www/watchcat_backup.html
Normal file
351
Belowx65Toolkit/simpleadmin/www/watchcat_backup.html
Normal file
@@ -0,0 +1,351 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Simple Admin</title>
|
||||
<!-- <link
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
|
||||
rel="stylesheet"
|
||||
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||
crossorigin="anonymous"
|
||||
/> -->
|
||||
<!-- Import all the bootstrap css files from css folder -->
|
||||
<link rel="stylesheet" href="css/styles.css" />
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css" />
|
||||
|
||||
<!-- Logo -->
|
||||
<link rel="simpleadmin-logo" href="favicon.ico" />
|
||||
|
||||
<!-- Import BootStrap Javascript -->
|
||||
<script src="js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/alpinejs.min.js" defer></script>
|
||||
|
||||
<style>
|
||||
.form-switch .form-check-input {
|
||||
width: 2.4em;
|
||||
height: 1.2em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<div class="container my-4" x-data="simpleWatchCat()">
|
||||
<nav class="navbar navbar-expand-lg mt-2">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="/"
|
||||
><span class="mb-0 h4">Simple Admin</span></a
|
||||
>
|
||||
<button
|
||||
class="navbar-toggler"
|
||||
type="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-target="#navbarText"
|
||||
aria-controls="navbarText"
|
||||
aria-expanded="false"
|
||||
aria-label="Toggle navigation"
|
||||
>
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarText">
|
||||
<ul class="navbar-nav me-auto mb-2 ml-4 mb-lg-0">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/">Home</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/network.html">Simple Network</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a
|
||||
class="nav-link active"
|
||||
href="/settings.html"
|
||||
aria-current="page"
|
||||
>Simple Settings</a
|
||||
>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/sms.html">SMS</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/console">Console</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="/deviceinfo.html"
|
||||
>Device Information</a
|
||||
>
|
||||
</li>
|
||||
</ul>
|
||||
<span class="navbar-text">
|
||||
<button class="btn btn-link text-reset" id="darkModeToggle">
|
||||
Dark Mode
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="row mt-3 mb-4">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Simple Watchcat</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="row mt-3 mb-5 align-content-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3">
|
||||
<label> Enable Watchcat </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="mt-2">
|
||||
<div class="form-check form-switch form-switch-lg">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="watchCatSwitch"
|
||||
x-model="watchCatStatus"
|
||||
:disabled="!isFormComplete"
|
||||
x:onchange="setWatchCatSettings"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3 mb-3 align-items-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Track IP </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Ping Request Timeout </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Ping Failure Amount </label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-5">
|
||||
<div class="mt-3 mb-4">
|
||||
<select
|
||||
class="form-select"
|
||||
aria-label="Select Site to Ping"
|
||||
x-model="trackIP"
|
||||
>
|
||||
<option selected>Select IP</option>
|
||||
<option value="1.1.1.1">1.1.1.1</option>
|
||||
<option value="8.8.8.8">8.8.8.8</option>
|
||||
<option value="9.9.9.9">9.9.9.9</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="Ping Timeout"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Enter Ping Timeout in Seconds."
|
||||
x-model="pingTimeout"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="Sizing example input"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Enter Ping Failure Amount."
|
||||
x-model="pingFailureCount"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="row mt-3 mb-5 align-content-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3">
|
||||
<label>Sim Auto Switch</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="mt-2">
|
||||
<div class="form-check form-switch form-switch-lg">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="simAutoSwitch"
|
||||
x-model="simAutoSwitchStatus"
|
||||
disabled
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- <div class="row mt-3 mb-3 align-items-center mx-4">
|
||||
<div class="col">
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Select Preferred SIM </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> SIM 1 APN </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> SIM 2 APN </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Failover Interval </label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<label> Scheduled SIM Hot Swap</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-5">
|
||||
<div class="mt-3 mb-3">
|
||||
<select
|
||||
class="form-select"
|
||||
aria-label="Select Sim"
|
||||
x-model="preferredSim"
|
||||
>
|
||||
<option selected>Select SIM</option>
|
||||
<option value="1">SIM 1</option>
|
||||
<option value="2">SIM 2</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-3">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="SIM 1 APN"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Input APN for SIM 1. (Optional)"
|
||||
x-model="sim1APN"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-3">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control"
|
||||
aria-label="SIM 2 APN"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
placeholder="Input APN for SIM 2. (Optional)"
|
||||
x-model="sim2APN"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-3 d-flex align-items-center">
|
||||
<select
|
||||
class="form-select"
|
||||
aria-label="Failover Interval"
|
||||
>
|
||||
<option selected>Failover Interval</option>
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="15">15</option>
|
||||
<option value="20">20</option>
|
||||
</select>
|
||||
<label class="mx-3">Minutes</label>
|
||||
</div>
|
||||
|
||||
<div class="mt-3 mb-3">
|
||||
<input
|
||||
type="time"
|
||||
class="form-control"
|
||||
aria-label="Scheduled SIM Hot Swap"
|
||||
aria-describedby="inputGroup-sizing-default"
|
||||
x-model="scheduledSIMHotSwap"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<!-- Setting a low ping timeout and ping failure count may cause
|
||||
intermittent disconnections due to high sensitivity. <br />
|
||||
Select appropriate values for both based on your needs.<br /> -->
|
||||
Still under development. Coming soon...
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3 mb-3">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Simple Watchcat Logs</div>
|
||||
<div class="card-body">
|
||||
<div class="card-text">
|
||||
<div class="form-floating">
|
||||
<textarea
|
||||
class="form-control"
|
||||
placeholder="Leave a comment here"
|
||||
id="floatingTextarea2"
|
||||
style="height: 100px"
|
||||
x-text="response"
|
||||
readonly
|
||||
></textarea>
|
||||
<label for="floatingTextarea2">Logs Here</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<script src="js/dark-mode.js"></script>
|
||||
<script>
|
||||
function simpleWatchCat() {
|
||||
return {
|
||||
watchCatStatus: false,
|
||||
trackIP: "",
|
||||
pingTimeout: "",
|
||||
pingFailureCount: "",
|
||||
response: "",
|
||||
|
||||
setWatchCatSettings() {
|
||||
fetch(
|
||||
"/cgi-bin/watchcat_maker?" +
|
||||
new URLSearchParams({
|
||||
WATCHCAT_ENABLED: this.watchCatStatus,
|
||||
TRACK_IP: this.trackIP,
|
||||
PING_TIMEOUT: this.pingTimeout,
|
||||
PING_FAILURE_COUNT: this.pingFailureCount,
|
||||
})
|
||||
)
|
||||
.then((response) => response.text()) // Convert response to text
|
||||
.then((data) => {
|
||||
this.response = data; // Store the response data
|
||||
console.log(data); // Log the response for debugging
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error); // Handle any errors
|
||||
this.response = "An error occurred.";
|
||||
});
|
||||
},
|
||||
|
||||
// Computed property to check if the form is complete
|
||||
get isFormComplete() {
|
||||
return (
|
||||
this.trackIP !== "" &&
|
||||
this.pingTimeout !== "" &&
|
||||
this.pingFailureCount !== ""
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1
Belowx65Toolkit/simplefirewall/.rev
Normal file
1
Belowx65Toolkit/simplefirewall/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
16
Belowx65Toolkit/simplefirewall/simplefirewall.sh
Normal file
16
Belowx65Toolkit/simplefirewall/simplefirewall.sh
Normal file
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define the ports you want to block
|
||||
PORTS=("80" "443") # Default ports, will be modified by the install script
|
||||
|
||||
# First, allow specified ports on bridge0, eth0, and tailscale0
|
||||
for port in "${PORTS[@]}"; do
|
||||
iptables -A INPUT -i bridge0 -p tcp --dport $port -j ACCEPT
|
||||
iptables -A INPUT -i eth0 -p tcp --dport $port -j ACCEPT
|
||||
iptables -A INPUT -i tailscale0 -p tcp --dport $port -j ACCEPT
|
||||
done
|
||||
|
||||
# Then, block specified ports on all other interfaces
|
||||
for port in "${PORTS[@]}"; do
|
||||
iptables -A INPUT -p tcp --dport $port -j DROP
|
||||
done
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Simple Firewall Setup
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash /usrdata/simplefirewall/simplefirewall.sh
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
12
Belowx65Toolkit/simplefirewall/systemd/ttl-override.service
Normal file
12
Belowx65Toolkit/simplefirewall/systemd/ttl-override.service
Normal file
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=TTL Override
|
||||
After=ql-netd.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usrdata/simplefirewall/ttl-override start
|
||||
User=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
53
Belowx65Toolkit/simplefirewall/ttl-override
Normal file
53
Belowx65Toolkit/simplefirewall/ttl-override
Normal file
@@ -0,0 +1,53 @@
|
||||
#! /bin/bash
|
||||
|
||||
# Adapted from https://github.com/natecarlson/quectel-rgmii-configuration-notes/blob/main/files/ttl-override
|
||||
# Uses ttlvalue file to read what ttl should be set to
|
||||
|
||||
|
||||
if [ -f /usrdata/simplefirewall/ttlvalue ];
|
||||
then
|
||||
ttlfile=$(</usrdata/simplefirewall/ttlvalue)
|
||||
TTLVALUE=$(echo $ttlfile | grep -o "[0-9]\{1,3\}")
|
||||
|
||||
if [ -z "${TTLVALUE}" ]; then
|
||||
echo "Couldnt get proper ttl value from file" >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Couldnt find ttlvalue file, lets generate one with 0 ttlvalue (0 = disabled)
|
||||
touch /usrdata/simplefirewall/ttlvalue && echo '0' > /usrdata/simplefirewall/ttlvalue
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if (( $TTLVALUE > 0 )); then
|
||||
echo "Adding TTL override rules: "
|
||||
iptables -t mangle -I POSTROUTING -o rmnet+ -j TTL --ttl-set ${TTLVALUE}
|
||||
ip6tables -t mangle -I POSTROUTING -o rmnet+ -j HL --hl-set ${TTLVALUE}
|
||||
else
|
||||
echo "TTLVALUE set to 0, nothing to do..."
|
||||
fi
|
||||
echo "done"
|
||||
;;
|
||||
stop)
|
||||
if (( $TTLVALUE > 0 )); then
|
||||
echo "Removing TTL override rules: "
|
||||
iptables -t mangle -D POSTROUTING -o rmnet+ -j TTL --ttl-set ${TTLVALUE} &>/dev/null || true
|
||||
ip6tables -t mangle -D POSTROUTING -o rmnet+ -j HL --hl-set ${TTLVALUE} &>/dev/null || true
|
||||
else
|
||||
echo "TTLVALUE set to 0, nothing to do..."
|
||||
fi
|
||||
echo "done"
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
$0 start
|
||||
;;
|
||||
*)
|
||||
echo "Usage ttl-override { start | stop | restart }" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
1
Belowx65Toolkit/simplefirewall/ttlvalue
Normal file
1
Belowx65Toolkit/simplefirewall/ttlvalue
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
Belowx65Toolkit/simpleupdates/.rev
Normal file
1
Belowx65Toolkit/simpleupdates/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
238
Belowx65Toolkit/simpleupdates/scripts/update_simpleadmin.sh
Normal file
238
Belowx65Toolkit/simpleupdates/scripts/update_simpleadmin.sh
Normal file
@@ -0,0 +1,238 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="simpleadmin"
|
||||
SERVICE_FILE="/lib/systemd/system/install_simpleadmin.service"
|
||||
SERVICE_NAME="install_simpleadmin"
|
||||
TMP_SCRIPT="/tmp/install_simpleadmin.sh"
|
||||
LOG_FILE="/tmp/install_simpleadmin.log"
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
|
||||
# Tmp Script dependent constants
|
||||
SIMPLE_ADMIN_DIR="/usrdata/simpleadmin"
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
# Installation Prep
|
||||
remount_rw
|
||||
systemctl daemon-reload
|
||||
rm $SERVICE_FILE > /dev/null 2>&1
|
||||
rm $SERVICE_NAME > /dev/null 2>&1
|
||||
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
SIMPLE_ADMIN_DIR="/usrdata/simpleadmin"
|
||||
export HOME=/usrdata/root
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
remount_rw
|
||||
uninstall_simpleadmin() {
|
||||
echo "Uninstalling Simpleadmin..."
|
||||
|
||||
# Check if Lighttpd service is installed and remove it if present
|
||||
if [ -f "/lib/systemd/system/lighttpd.service" ]; then
|
||||
echo "Lighttpd detected, uninstalling Lighttpd webserver and its modules..."
|
||||
systemctl stop lighttpd
|
||||
rm -f /lib/systemd/system/lighttpd.service
|
||||
opkg --force-remove --force-removal-of-dependent-packages remove lighttpd-mod-authn_file lighttpd-mod-auth lighttpd-mod-cgi lighttpd-mod-openssl lighttpd-mod-proxy lighttpd
|
||||
fi
|
||||
echo -e "\e[1;34mUninstalling simpleadmin content...\e[0m"
|
||||
systemctl stop simpleadmin_generate_status
|
||||
systemctl stop simpleadmin_httpd
|
||||
rm -f /lib/systemd/system/simpleadmin_httpd.service
|
||||
rm -f /lib/systemd/system/simpleadmin_generate_status.service
|
||||
systemctl daemon-reload
|
||||
|
||||
echo -e "\e[1;34mUninstalling ttyd...\e[0m"
|
||||
systemctl stop ttyd
|
||||
rm -rf /usrdata/ttyd
|
||||
rm -rf "$SIMPLE_ADMIN_DIR"
|
||||
rm -f /lib/systemd/system/ttyd.service
|
||||
rm -f /lib/systemd/system/multi-user.target.wants/ttyd.service
|
||||
rm -f /bin/ttyd
|
||||
echo -e "\e[1;32mttyd has been uninstalled.\e[0m"
|
||||
|
||||
echo "Uninstallation process completed."
|
||||
}
|
||||
|
||||
install_lighttpd() {
|
||||
# Check for simpleadmin_httpd service and remove if exists
|
||||
if [ -f "/lib/systemd/system/simpleadmin_httpd.service" ]; then
|
||||
systemctl stop simpleadmin_httpd
|
||||
rm /lib/systemd/system/simpleadmin_httpd.service
|
||||
rm /lib/systemd/system/multi-user.target.wants/simpleadmin_httpd.service
|
||||
fi
|
||||
|
||||
/opt/bin/opkg install sudo lighttpd lighttpd-mod-auth lighttpd-mod-authn_file lighttpd-mod-cgi lighttpd-mod-openssl lighttpd-mod-proxy
|
||||
# Ensure rc.unslung doesn't try to start it
|
||||
# Dynamically find and remove any Lighttpd-related init script
|
||||
for script in /opt/etc/init.d/*lighttpd*; do
|
||||
if [ -f "$script" ]; then
|
||||
echo "Removing existing Lighttpd init script: $script"
|
||||
rm "$script" # Remove the script if it contains 'lighttpd' in its name
|
||||
fi
|
||||
done
|
||||
systemctl stop lighttpd
|
||||
echo -e "\033[0;32mInstalling/Updating Lighttpd...\033[0m"
|
||||
mkdir -p "$SIMPLE_ADMIN_DIR"
|
||||
wget -O "$SIMPLE_ADMIN_DIR/lighttpd.conf" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/lighttpd.conf
|
||||
wget -O "/lib/systemd/system/lighttpd.service" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/systemd/lighttpd.service
|
||||
ln -sf "/lib/systemd/system/lighttpd.service" "/lib/systemd/system/multi-user.target.wants/"
|
||||
echo "www-data ALL = (root) NOPASSWD: /usr/sbin/iptables, /usr/sbin/ip6tables, /usrdata/simplefirewall/ttl-override, /bin/echo, /bin/cat" > /opt/etc/sudoers.d/www-data
|
||||
|
||||
openssl req -new -newkey rsa:2048 -days 3650 -nodes -x509 \
|
||||
-subj "/C=US/ST=MI/L=Romulus/O=RMIITools/CN=localhost" \
|
||||
-keyout $SIMPLE_ADMIN_DIR/server.key -out $SIMPLE_ADMIN_DIR/server.crt
|
||||
systemctl daemon-reload
|
||||
systemctl start lighttpd
|
||||
|
||||
echo -e "\033[0;32mLighttpd installation/update complete.\033[0m"
|
||||
}
|
||||
|
||||
install_simpleadmin() {
|
||||
remount_rw
|
||||
echo -e "\e[1;31m2) Installing simpleadmin from the $GITTREE branch\e[0m"
|
||||
mkdir $SIMPLE_ADMIN_DIR
|
||||
mkdir $SIMPLE_ADMIN_DIR/systemd
|
||||
mkdir $SIMPLE_ADMIN_DIR/script
|
||||
mkdir $SIMPLE_ADMIN_DIR/console
|
||||
mkdir $SIMPLE_ADMIN_DIR/console/menu
|
||||
mkdir $SIMPLE_ADMIN_DIR/console/services
|
||||
mkdir $SIMPLE_ADMIN_DIR/console/services/systemd
|
||||
mkdir $SIMPLE_ADMIN_DIR/www
|
||||
mkdir $SIMPLE_ADMIN_DIR/www/cgi-bin
|
||||
mkdir $SIMPLE_ADMIN_DIR/www/css
|
||||
mkdir $SIMPLE_ADMIN_DIR/www/js
|
||||
cd $SIMPLE_ADMIN_DIR/systemd
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/systemd/lighttpd.service
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/script
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/script/ttl_script.sh
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/script/remove_watchcat.sh
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/script/create_watchcat.sh
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/console
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/console/.profile
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/console/menu
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/console/menu/start_menu.sh
|
||||
ln -f $SIMPLE_ADMIN_DIR/console/menu/start_menu.sh /usrdata/root/bin/menu
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/console/menu/sfirewall_settings.sh
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/console/menu/start_menu.sh
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/www
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/deviceinfo.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/favicon.ico
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/index.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/network.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/settings.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/sms.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/scanner.html
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/watchcat.html
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/www/js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/alpinejs.min.js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/bootstrap.bundle.min.js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/dark-mode.js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/generate-freq-box.js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/parse-settings.js
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/js/populate-checkbox.js
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/www/css
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/css/bootstrap.min.css
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/css/styles.css
|
||||
sleep 1
|
||||
cd $SIMPLE_ADMIN_DIR/www/cgi-bin
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_atcommand
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_ping
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_sms
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_ttl_status
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/set_ttl
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/send_sms
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_uptime
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/get_watchcat_status
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/set_watchcat
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/www/cgi-bin/watchcat_maker
|
||||
sleep 1
|
||||
cd /
|
||||
chmod +x $SIMPLE_ADMIN_DIR/www/cgi-bin/*
|
||||
chmod +x $SIMPLE_ADMIN_DIR/script/*
|
||||
chmod +x $SIMPLE_ADMIN_DIR/console/menu/*
|
||||
chmod +x $SIMPLE_ADMIN_DIR/console/.profile
|
||||
cp -f $SIMPLE_ADMIN_DIR/console/.profile /usrdata/root/.profile
|
||||
chmod +x /usrdata/root/.profile
|
||||
cp -rf $SIMPLE_ADMIN_DIR/systemd/* /lib/systemd/system
|
||||
sleep 1
|
||||
systemctl daemon-reload
|
||||
sleep 1
|
||||
}
|
||||
install_ttyd() {
|
||||
echo -e "\e[1;34mStarting ttyd installation process...\e[0m"
|
||||
cd $SIMPLE_ADMIN_DIR/console
|
||||
curl -L -o ttyd https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.armhf && chmod +x ttyd
|
||||
wget "https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/console/ttyd.bash" && chmod +x ttyd.bash
|
||||
cd $SIMPLE_ADMIN_DIR/systemd/
|
||||
wget "https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simpleadmin/systemd/ttyd.service"
|
||||
cp -f $SIMPLE_ADMIN_DIR/systemd/ttyd.service /lib/systemd/system/
|
||||
ln -sf /usrdata/simpleadmin/ttyd /bin
|
||||
|
||||
# Enabling and starting ttyd service
|
||||
systemctl daemon-reload
|
||||
ln -sf /lib/systemd/system/ttyd.service /lib/systemd/system/multi-user.target.wants/
|
||||
systemctl start ttyd
|
||||
if [ "$?" -ne 0 ]; then
|
||||
echo -e "\e[1;31mFailed to start ttyd service. Please check the systemd service file and ttyd binary.\e[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "\e[1;32mInstallation Complete! ttyd server is up.\e[0m"
|
||||
}
|
||||
uninstall_simpleadmin
|
||||
install_lighttpd
|
||||
install_simpleadmin
|
||||
install_ttyd
|
||||
remount_ro
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
106
Belowx65Toolkit/simpleupdates/scripts/update_simplefirewall.sh
Normal file
106
Belowx65Toolkit/simpleupdates/scripts/update_simplefirewall.sh
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="simplefirewall"
|
||||
SERVICE_FILE="/lib/systemd/system/install_simplefirewall.service"
|
||||
SERVICE_NAME="install_simplefirewall"
|
||||
TMP_SCRIPT="/tmp/install_simple_firewall.sh"
|
||||
LOG_FILE="/tmp/install_simplefirewall.log"
|
||||
|
||||
# Tmp Script dependent constants
|
||||
SIMPLE_FIREWALL_DIR="/usrdata/simplefirewall"
|
||||
SIMPLE_FIREWALL_SCRIPT="$SIMPLE_FIREWALL_DIR/simplefirewall.sh"
|
||||
SIMPLE_FIREWALL_SYSTEMD_DIR="$SIMPLE_FIREWALL_DIR/systemd"
|
||||
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
remount_rw
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
SIMPLE_FIREWALL_DIR="/usrdata/simplefirewall"
|
||||
SIMPLE_FIREWALL_SCRIPT="$SIMPLE_FIREWALL_DIR/simplefirewall.sh"
|
||||
SIMPLE_FIREWALL_SYSTEMD_DIR="$SIMPLE_FIREWALL_DIR/systemd"
|
||||
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
remount_rw
|
||||
# Function to remove Simple Firewall
|
||||
uninstall_simple_firewall() {
|
||||
echo "Uninstalling Simplefirewall..."
|
||||
systemctl stop simplefirewall
|
||||
systemctl stop ttl-override
|
||||
rm -f /lib/systemd/system/simplefirewall.service
|
||||
rm -f /lib/systemd/system/ttl-override.service
|
||||
systemctl daemon-reload
|
||||
rm -rf "$SIMPLE_FIREWALL_DIR"
|
||||
echo "Simplefirewall uninstalled."
|
||||
}
|
||||
# Function to install Simple Firewall
|
||||
install_simple_firewall() {
|
||||
systemctl stop simplefirewall
|
||||
systemctl stop ttl-override
|
||||
echo -e "\033[0;32mInstalling/Updating Simple Firewall...\033[0m"
|
||||
mount -o remount,rw /
|
||||
mkdir -p "$SIMPLE_FIREWALL_DIR"
|
||||
mkdir -p "$SIMPLE_FIREWALL_SYSTEMD_DIR"
|
||||
wget -O "$SIMPLE_FIREWALL_DIR/simplefirewall.sh" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simplefirewall/simplefirewall.sh
|
||||
wget -O "$SIMPLE_FIREWALL_DIR/ttl-override" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simplefirewall/ttl-override
|
||||
wget -O "$SIMPLE_FIREWALL_DIR/ttlvalue" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simplefirewall/ttlvalue
|
||||
chmod 666 $SIMPLE_FIREWALL_DIR/ttlvalue
|
||||
chmod +x "$SIMPLE_FIREWALL_DIR/simplefirewall.sh"
|
||||
chmod +x "$SIMPLE_FIREWALL_DIR/ttl-override"
|
||||
wget -O "$SIMPLE_FIREWALL_SYSTEMD_DIR/simplefirewall.service" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simplefirewall/systemd/simplefirewall.service
|
||||
wget -O "$SIMPLE_FIREWALL_SYSTEMD_DIR/ttl-override.service" https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/simplefirewall/systemd/ttl-override.service
|
||||
cp -rf $SIMPLE_FIREWALL_SYSTEMD_DIR/* /lib/systemd/system
|
||||
ln -sf "/lib/systemd/system/simplefirewall.service" "/lib/systemd/system/multi-user.target.wants/"
|
||||
ln -sf "/lib/systemd/system/ttl-override.service" "/lib/systemd/system/multi-user.target.wants/"
|
||||
systemctl daemon-reload
|
||||
systemctl start simplefirewall
|
||||
systemctl start ttl-override
|
||||
echo -e "\033[0;32mSimple Firewall installation/update complete.\033[0m"
|
||||
}
|
||||
uninstall_simple_firewall
|
||||
install_simple_firewall
|
||||
remount_ro
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/bin/bash
|
||||
|
||||
# WORK IN PROGRESS
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="simpleupdates"
|
||||
SERVICE_FILE="/lib/systemd/system/install_simpleupdates.service"
|
||||
SERVICE_NAME="install_simpleupdates"
|
||||
TMP_SCRIPT="/tmp/install_simpleupdates.sh"
|
||||
LOG_FILE="/tmp/install_simpleupdates.log"
|
||||
|
||||
# Tmp Script dependent constants
|
||||
|
||||
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
install_simpleupdates() {
|
||||
# CONTENT
|
||||
}
|
||||
install_simpleupdates
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
147
Belowx65Toolkit/simpleupdates/scripts/update_socat-at-bridge.sh
Normal file
147
Belowx65Toolkit/simpleupdates/scripts/update_socat-at-bridge.sh
Normal file
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="socat-at-bridge"
|
||||
SERVICE_FILE="/lib/systemd/system/install_socat-at-bridge.service"
|
||||
SERVICE_NAME="install_socat-at-bridge"
|
||||
TMP_SCRIPT="/tmp/install_socat-at-bridge.sh"
|
||||
LOG_FILE="/tmp/install_socat-at-bridge.log"
|
||||
|
||||
# Tmp Script dependent constants
|
||||
SOCAT_AT_DIR="/usrdata/socat-at-bridge"
|
||||
SOCAT_AT_SYSD_DIR="/usrdata/socat-at-bridge/systemd_units"
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
remount_rw
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
SOCAT_AT_DIR="/usrdata/socat-at-bridge"
|
||||
SOCAT_AT_SYSD_DIR="/usrdata/socat-at-bridge/systemd_units"
|
||||
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
remount_rw
|
||||
uninstall_at_socat() {
|
||||
echo -e "\033[0;32mRemoving installed AT Socat Bridge services...\033[0m"
|
||||
systemctl stop at-telnet-daemon > /dev/null 2>&1
|
||||
systemctl disable at-telnet-daemon > /dev/null 2>&1
|
||||
systemctl stop socat-smd11 > /dev/null 2>&1
|
||||
systemctl stop socat-smd11-to-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd11-from-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd7 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-to-ttyIN2 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-to-ttyIN > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-from-ttyIN2 > /dev/null 2>&1
|
||||
systemctl stop socat-smd7-from-ttyIN > /dev/null 2>&1
|
||||
rm /lib/systemd/system/at-telnet-daemon.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11-to-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd11-from-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-to-ttyIN2.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-to-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-from-ttyIN.service > /dev/null 2>&1
|
||||
rm /lib/systemd/system/socat-smd7-from-ttyIN2.service > /dev/null 2>&1
|
||||
systemctl daemon-reload > /dev/null 2>&1
|
||||
rm -rf "$SOCAT_AT_DIR" > /dev/null 2>&1
|
||||
}
|
||||
|
||||
install_at_socat() {
|
||||
# Install service units
|
||||
echo -e "\033[0;32mInstalling AT Socat Bridge services...\033[0m"
|
||||
mkdir $SOCAT_AT_DIR
|
||||
cd $SOCAT_AT_DIR
|
||||
mkdir $SOCAT_AT_SYSD_DIR
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/socat-armel-static
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/killsmd7bridge
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/atcmd
|
||||
cd $SOCAT_AT_SYSD_DIR
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd11.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd11-from-ttyIN.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd11-to-ttyIN.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-killsmd7bridge.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd7-from-ttyIN2.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd7-to-ttyIN2.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/socat-at-bridge/systemd_units/socat-smd7.service
|
||||
|
||||
# Set execute permissions
|
||||
cd $SOCAT_AT_DIR
|
||||
chmod +x socat-armel-static
|
||||
chmod +x killsmd7bridge
|
||||
chmod +x atcmd
|
||||
|
||||
# Link new command for AT Commands from the shell
|
||||
ln -sf $SOCAT_AT_DIR/atcmd /bin
|
||||
|
||||
# Install service units
|
||||
echo -e "\033[0;32mAdding AT Socat Bridge systemd service units...\033[0m"
|
||||
cp -rf $SOCAT_AT_SYSD_DIR/*.service /lib/systemd/system
|
||||
ln -sf /lib/systemd/system/socat-killsmd7bridge.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd11.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd11-to-ttyIN.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd11-from-ttyIN.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd7.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd7-to-ttyIN2.service /lib/systemd/system/multi-user.target.wants/
|
||||
ln -sf /lib/systemd/system/socat-smd7-from-ttyIN2.service /lib/systemd/system/multi-user.target.wants/
|
||||
systemctl daemon-reload
|
||||
systemctl start socat-smd11
|
||||
sleep 2s
|
||||
systemctl start socat-smd11-to-ttyIN
|
||||
systemctl start socat-smd11-from-ttyIN
|
||||
echo -e "\033[0;32mAT Socat Bridge service online: smd11 to ttyOUT\033[0m"
|
||||
systemctl start socat-killsmd7bridge
|
||||
sleep 1s
|
||||
systemctl start socat-smd7
|
||||
sleep 2s
|
||||
systemctl start socat-smd7-to-ttyIN2
|
||||
systemctl start socat-smd7-from-ttyIN2
|
||||
echo -e "\033[0;32mAT Socat Bridge service online: smd7 to ttyOUT2\033[0m"
|
||||
remount_ro
|
||||
cd /
|
||||
echo -e "\033[0;32mAT Socat Bridge services Installed!\033[0m"
|
||||
}
|
||||
uninstall_at_socat
|
||||
install_at_socat
|
||||
remount_ro
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
73
Belowx65Toolkit/simpleupdates/scripts/update_sshd.sh
Normal file
73
Belowx65Toolkit/simpleupdates/scripts/update_sshd.sh
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="simpleupdates"
|
||||
SERVICE_FILE="/lib/systemd/system/install_sshd.service"
|
||||
SERVICE_NAME="install_sshd"
|
||||
TMP_SCRIPT="/tmp/install_sshd.sh"
|
||||
LOG_FILE="/tmp/install_sshd.log"
|
||||
|
||||
# Tmp Script dependent constants
|
||||
|
||||
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
|
||||
install_sshd() {
|
||||
echo -e "\e[1;32mOpenSSH Server\e[0m"
|
||||
remount_rw
|
||||
|
||||
mkdir /usrdata/sshd
|
||||
wget -O /lib/systemd/system/sshd.service "https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE/sshd/sshd.service"
|
||||
ln -sf "/lib/systemd/system/sshd.service" "/lib/systemd/system/multi-user.target.wants/"
|
||||
|
||||
opkg install openssh-server-pam
|
||||
for script in /opt/etc/init.d/*sshd*; do
|
||||
if [ -f "$script" ]; then
|
||||
echo "Removing existing sshd init script: $script"
|
||||
rm "$script" # Remove the script if it contains 'sshd' in its name
|
||||
fi
|
||||
done
|
||||
/opt/bin/ssh-keygen -A
|
||||
systemctl daemon-reload
|
||||
systemctl enable sshd
|
||||
|
||||
# Enable PAM and PermitRootLogin
|
||||
sed -i "s/^.*UsePAM .*/UsePAM yes/" "/opt/etc/ssh/sshd_config"
|
||||
sed -i "s/^.*PermitRootLogin .*/PermitRootLogin yes/" "/opt/etc/ssh/sshd_config"
|
||||
|
||||
# Ensure the sshd user exists in the /opt/etc/passwd file
|
||||
grep "sshd:x:106" /opt/etc/passwd || echo "sshd:x:106:65534:Linux User,,,:/opt/run/sshd:/bin/nologin" >> /opt/etc/passwd
|
||||
systemctl start sshd
|
||||
|
||||
echo -e "\e[1;32mOpenSSH installed!!\e[0m"
|
||||
}
|
||||
install_sshd
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
116
Belowx65Toolkit/simpleupdates/scripts/update_tailscale.sh
Normal file
116
Belowx65Toolkit/simpleupdates/scripts/update_tailscale.sh
Normal file
@@ -0,0 +1,116 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Define constants
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
DIR_NAME="tailscale"
|
||||
SERVICE_FILE="/lib/systemd/system/install_tailscale.service"
|
||||
SERVICE_NAME="install_tailscale"
|
||||
TMP_SCRIPT="/tmp/install_tailscale.sh"
|
||||
LOG_FILE="/tmp/install_sshd.log"
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
|
||||
# Tmp Script dependent constants
|
||||
TAILSCALE_DIR="/usrdata/tailscale/"
|
||||
TAILSCALE_SYSD_DIR="/usrdata/tailscale/systemd"
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
# Installation Prep
|
||||
remount_rw
|
||||
systemctl daemon-reload
|
||||
rm $SERVICE_FILE > /dev/null 2>&1
|
||||
rm $SERVICE_NAME > /dev/null 2>&1
|
||||
|
||||
# Create the systemd service file
|
||||
cat <<EOF > "$SERVICE_FILE"
|
||||
[Unit]
|
||||
Description=Update $DIR_NAME temporary service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/bash $TMP_SCRIPT > $LOG_FILE 2>&1
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
# Create and populate the temporary shell script for installation
|
||||
cat <<EOF > "$TMP_SCRIPT"
|
||||
#!/bin/bash
|
||||
|
||||
export HOME=/usrdata/root
|
||||
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/opt/bin:/opt/sbin:/usrdata/root/bin
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="development"
|
||||
TAILSCALE_DIR="/usrdata/tailscale/"
|
||||
TAILSCALE_SYSD_DIR="/usrdata/tailscale/systemd"
|
||||
|
||||
# Function to remount file system as read-write
|
||||
remount_rw() {
|
||||
mount -o remount,rw /
|
||||
}
|
||||
|
||||
# Function to remount file system as read-only
|
||||
remount_ro() {
|
||||
mount -o remount,ro /
|
||||
}
|
||||
|
||||
install_update_tailscale() {
|
||||
echo "Checking if Tailscale is already installed..."
|
||||
if [ -f "$TAILSCALE_DIR/tailscale" ]; then
|
||||
echo "Tailscale binary found. Updating Tailscale..."
|
||||
ln -sf "$TAILSCALE_DIR/tailscale" "/usrdata/root/bin/tailscale"
|
||||
echo y | $TAILSCALE_DIR/tailscale update
|
||||
echo -e "\e[32mTailscale updated!\e[0m"
|
||||
remount_ro
|
||||
exit 0
|
||||
else
|
||||
echo "Installing Tailscale..."
|
||||
mkdir -p "$TAILSCALE_DIR" "$TAILSCALE_SYSD_DIR"
|
||||
echo "Downloading binary files..."
|
||||
cd /usrdata
|
||||
curl -O https://pkgs.tailscale.com/stable/tailscale_1.66.4_arm.tgz
|
||||
tar -xzf tailscale_1.66.4_arm.tgz
|
||||
rm tailscale_1.66.4_arm.tgz
|
||||
cd /usrdata/tailscale_1.66.4_arm
|
||||
mv tailscale tailscaled "$TAILSCALE_DIR/"
|
||||
rm -rf /usrdata/tailscale_1.66.4_arm
|
||||
echo "Downloading systemd files..."
|
||||
cd "$TAILSCALE_SYSD_DIR"
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/main/tailscale/systemd/tailscaled.service
|
||||
wget https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/main/tailscale/systemd/tailscaled.defaults
|
||||
sleep 2s
|
||||
echo "Setting Permissions..."
|
||||
chmod +x "$TAILSCALE_DIR/tailscaled" "$TAILSCALE_DIR/tailscale"
|
||||
echo "Copying systemd units..."
|
||||
cp -rf "$TAILSCALE_SYSD_DIR"/* /lib/systemd/system/
|
||||
ln -sf /lib/systemd/system/tailscaled.service /lib/systemd/system/multi-user.target.wants/
|
||||
systemctl daemon-reload
|
||||
echo "Starting Tailscaled..."
|
||||
systemctl start tailscaled
|
||||
cd /
|
||||
remount_ro
|
||||
echo -e "\e[32mTailscale installed successfully.\e[0m"
|
||||
exit 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute the function
|
||||
install_update_tailscale
|
||||
exit 0
|
||||
EOF
|
||||
|
||||
# Make the temporary script executable
|
||||
chmod +x "$TMP_SCRIPT"
|
||||
|
||||
# Reload systemd to recognize the new service and start the update
|
||||
systemctl daemon-reload
|
||||
systemctl start $SERVICE_NAME
|
||||
12
Belowx65Toolkit/simpleupdates/simpleadmin.conf
Normal file
12
Belowx65Toolkit/simpleupdates/simpleadmin.conf
Normal file
@@ -0,0 +1,12 @@
|
||||
# Enable or disable update checks
|
||||
CONF_ENABLED=no
|
||||
# Check for updates at boot
|
||||
CHECK_AT_BOOT=no
|
||||
# Update frequency: daily, weekly, monthly, or none
|
||||
UPDATE_FREQUENCY=none
|
||||
# Scheduled time for updates (24-hour UTC format)
|
||||
SCHEDULED_TIME=00:00
|
||||
# Day for weekly updates (e.g., Mon, Tues, Wed, Thurs, Fri)
|
||||
WEEKLY_DAY=
|
||||
# Date for monthly updates (e.g., 15 for the 15th of the month)
|
||||
MONTHLY_DATE=
|
||||
255
Belowx65Toolkit/simpleupdates/simpleupdate
Normal file
255
Belowx65Toolkit/simpleupdates/simpleupdate
Normal file
@@ -0,0 +1,255 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Configuration and directories
|
||||
CONFIG_FILE="/usrdata/simpleupdates/simpleupdate.conf"
|
||||
GITUSER="iamromulan"
|
||||
GITTREE="main"
|
||||
DIRECTORIES=("simpleadmin" "socat-at-bridge" "simplefirewall" "tailscale" "ttyd")
|
||||
BASE_URL="https://raw.githubusercontent.com/$GITUSER/quectel-rgmii-toolkit/$GITTREE"
|
||||
LOG_FILE="/tmp/simpleupdate.log"
|
||||
|
||||
# Load configuration
|
||||
load_config() {
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
source "$CONFIG_FILE"
|
||||
else
|
||||
echo "Configuration file ($CONFIG_FILE) not found."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to trim the log file to the last 100 lines
|
||||
trim_log_file() {
|
||||
tail -n 100 "$LOG_FILE" > "$LOG_FILE.tmp" && mv "$LOG_FILE.tmp" "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Function to check for updates
|
||||
check_for_updates() {
|
||||
echo "$(date): Checking for updates..."
|
||||
for dir in "${DIRECTORIES[@]}"; do
|
||||
local remote_rev=$(wget -qO- "$BASE_URL/$dir/.rev")
|
||||
local local_rev_file="/usrdata/$dir/.rev"
|
||||
|
||||
if [[ ! -f "$local_rev_file" ]]; then
|
||||
echo "No local revision file found for $dir, skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
local local_rev=$(cat "$local_rev_file")
|
||||
|
||||
if [[ "$remote_rev" -gt "$local_rev" ]]; then
|
||||
echo "Update available for $dir, updating..."
|
||||
wget -qO "/tmp/update_${dir}.sh" "$BASE_URL/simpleupdates/scripts/update_${dir}.sh"
|
||||
chmod +x "/tmp/update_${dir}.sh"
|
||||
"/tmp/update_${dir}.sh"
|
||||
else
|
||||
echo "$dir is up to date."
|
||||
fi
|
||||
done
|
||||
trim_log_file
|
||||
wait_to_update
|
||||
}
|
||||
|
||||
# Function to wait and trigger updates based on scheduling
|
||||
wait_to_update() {
|
||||
echo "Waiting for the next update check according to schedule..."
|
||||
while true; do
|
||||
local current_time=$(date "+%H:%M")
|
||||
local current_day=$(date "+%a")
|
||||
local current_date=$(date "+%d")
|
||||
|
||||
case $UPDATE_FREQUENCY in
|
||||
daily)
|
||||
if [[ "$current_time" == "$SCHEDULED_TIME" ]]; then
|
||||
check_for_updates
|
||||
fi
|
||||
;;
|
||||
weekly)
|
||||
if [[ "$current_day" == "$WEEKLY_DAY" && "$current_time" == "$SCHEDULED_TIME" ]]; then
|
||||
check_for_updates
|
||||
fi
|
||||
;;
|
||||
monthly)
|
||||
if [[ "$current_date" == "$MONTHLY_DATE" && "$current_time" == "$SCHEDULED_TIME" ]]; then
|
||||
check_for_updates
|
||||
fi
|
||||
;;
|
||||
none)
|
||||
echo "Update checking is disabled by frequency setting."
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
sleep 30 # Sleep for 30 seconds for more granular checks
|
||||
trim_log_file
|
||||
done
|
||||
}
|
||||
|
||||
# Daemon mode to wait and trigger updates based on scheduling
|
||||
daemon_mode() {
|
||||
load_config
|
||||
exec > >(tee -a "$LOG_FILE") 2>&1
|
||||
echo "Daemon mode started."
|
||||
# Validate only one update frequency is defined
|
||||
frequency_count=0
|
||||
[[ "$UPDATE_FREQUENCY" == "daily" ]] && ((frequency_count++))
|
||||
[[ "$UPDATE_FREQUENCY" == "weekly" ]] && ((frequency_count++))
|
||||
[[ "$UPDATE_FREQUENCY" == "monthly" ]] && ((frequency_count++))
|
||||
|
||||
if [[ $frequency_count -gt 1 ]]; then
|
||||
echo "Error: More than one update frequency is defined. Exiting."
|
||||
exit 1
|
||||
elif [[ $frequency_count -eq 0 && "$UPDATE_FREQUENCY" != "none" ]]; then
|
||||
echo "Error: No valid update frequency defined. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$CONF_ENABLED" == "no" ]]; then
|
||||
echo "Updates are disabled in the configuration."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$CHECK_AT_BOOT" == "yes" ]]; then
|
||||
check_for_updates
|
||||
else
|
||||
wait_to_update
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to check for updates
|
||||
force_check_for_updates() {
|
||||
echo "$(date): Checking for updates..."
|
||||
for dir in "${DIRECTORIES[@]}"; do
|
||||
local remote_rev=$(wget -qO- "$BASE_URL/$dir/.rev")
|
||||
local local_rev_file="/usrdata/$dir/.rev"
|
||||
|
||||
if [[ ! -f "$local_rev_file" ]]; then
|
||||
echo "No local revision file found for $dir, skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
local local_rev=$(cat "$local_rev_file")
|
||||
|
||||
if [[ "$remote_rev" -gt "$local_rev" ]]; then
|
||||
echo "Update available for $dir, updating..."
|
||||
wget -qO "/tmp/update_${dir}.sh" "$BASE_URL/simpleupdates/scripts/update_${dir}.sh"
|
||||
chmod +x "/tmp/update_${dir}.sh"
|
||||
"/tmp/update_${dir}.sh"
|
||||
else
|
||||
echo "$dir is up to date."
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Helper function to load and update the configuration
|
||||
update_config() {
|
||||
local key="$1"
|
||||
local value="$2"
|
||||
if grep -q "^$key=" "$CONFIG_FILE"; then
|
||||
sed -i "s|^$key=.*|$key=$value|" "$CONFIG_FILE"
|
||||
else
|
||||
echo "$key=$value" >> "$CONFIG_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Display the current configuration status
|
||||
status() {
|
||||
echo "Current Configuration Status:"
|
||||
if [[ -f "$CONFIG_FILE" ]]; then
|
||||
while IFS= read -r line; do
|
||||
echo "$line"
|
||||
done < "$CONFIG_FILE"
|
||||
else
|
||||
echo "Configuration file not found."
|
||||
fi
|
||||
}
|
||||
|
||||
# Enable automatic updates
|
||||
enable_updates() {
|
||||
update_config "CONF_ENABLED" "yes"
|
||||
echo "Automatic updates have been enabled."
|
||||
}
|
||||
|
||||
# Disable automatic updates
|
||||
disable_updates() {
|
||||
update_config "CONF_ENABLED" "no"
|
||||
echo "Automatic updates have been disabled."
|
||||
}
|
||||
|
||||
# Interactive setup for the update configuration
|
||||
setup() {
|
||||
read -p "Enable automatic updates? [yes/no]: " enable_updates
|
||||
if [[ "$enable_updates" == "yes" ]]; then
|
||||
enable_updates
|
||||
else
|
||||
disable_updates
|
||||
fi
|
||||
|
||||
read -p "Check for updates at boot? [yes/no]: " check_boot
|
||||
update_config "CHECK_AT_BOOT" "$check_boot"
|
||||
|
||||
read -p "Update frequency (none, daily, weekly, monthly): " frequency
|
||||
update_config "UPDATE_FREQUENCY" "$frequency"
|
||||
|
||||
case $frequency in
|
||||
daily)
|
||||
read -p "Scheduled time (HH:MM in 24-hour format): " time
|
||||
update_config "SCHEDULED_TIME" "$time"
|
||||
;;
|
||||
weekly)
|
||||
echo "Please enter the day of the week."
|
||||
read -p "Day (full name or abbreviation, e.g., Monday or Mon): " day_input
|
||||
# Normalize input to abbreviated form
|
||||
day_abbr=$(date -d "$day_input" +%a 2>/dev/null)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Invalid day of the week. Please try again."
|
||||
return 1
|
||||
fi
|
||||
update_config "WEEKLY_DAY" "$day_abbr"
|
||||
read -p "Scheduled time (HH:MM in 24-hour format): " time
|
||||
update_config "SCHEDULED_TIME" "$time"
|
||||
;;
|
||||
monthly)
|
||||
read -p "Date of the month (1-31): " date
|
||||
update_config "MONTHLY_DATE" "$date"
|
||||
read -p "Scheduled time (HH:MM in 24-hour format): " time
|
||||
update_config "SCHEDULED_TIME" "$time"
|
||||
;;
|
||||
*)
|
||||
echo "No scheduling will be set."
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Update configuration has been set."
|
||||
}
|
||||
|
||||
# Command operations: status, enable, disable, update, setup
|
||||
case "$1" in
|
||||
d)
|
||||
daemon_mode
|
||||
;;
|
||||
update)
|
||||
load_config
|
||||
force_check_for_updates
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
enable)
|
||||
enable_updates
|
||||
;;
|
||||
disable)
|
||||
disable_updates
|
||||
;;
|
||||
setup)
|
||||
setup
|
||||
;;
|
||||
*)
|
||||
echo "Usage:"
|
||||
echo "d: Run as a background check daemon"
|
||||
echo "update: Force check for and install updates"
|
||||
echo "status: Display current set update schedule"
|
||||
echo "enable: Enable automatic updates"
|
||||
echo "disable: Disable automatic updates"
|
||||
echo "setup: Set up an automatic update schedule"
|
||||
;;
|
||||
esac
|
||||
10
Belowx65Toolkit/simpleupdates/systemd/simpleupdated.service
Normal file
10
Belowx65Toolkit/simpleupdates/systemd/simpleupdated.service
Normal file
@@ -0,0 +1,10 @@
|
||||
[Unit]
|
||||
Description=Simple Update Daemon
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usrdata/simpleupdates/simpleupdate d
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
Belowx65Toolkit/socat-at-bridge/.rev
Normal file
1
Belowx65Toolkit/socat-at-bridge/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
69
Belowx65Toolkit/socat-at-bridge/atcmd
Normal file
69
Belowx65Toolkit/socat-at-bridge/atcmd
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/bin/bash
|
||||
|
||||
DEVICE=/dev/ttyOUT2
|
||||
BAUD=115200
|
||||
|
||||
# Function to setup device communication parameters
|
||||
setup_device() {
|
||||
stty -F $DEVICE cs8 $BAUD ignbrk -brkint -icrnl -imaxbel \
|
||||
-opost -onlcr -isig -icanon -iexten -echo -echoe -echok \
|
||||
-echoctl -echoke noflsh -ixon -crtscts
|
||||
}
|
||||
|
||||
# Function to send AT command and capture the output
|
||||
send_at_command() {
|
||||
local command="$1"
|
||||
|
||||
# Clear the device buffer before sending a new command
|
||||
echo -n > $DEVICE
|
||||
|
||||
# Send the AT command, preserving the integrity of the input
|
||||
echo -e "$command\r" > $DEVICE
|
||||
|
||||
# Use a temporary file to capture the command output
|
||||
tmpfile=$(mktemp)
|
||||
|
||||
# Start reading the device output to the temporary file
|
||||
cat $DEVICE > "$tmpfile" &
|
||||
CAT_PID=$!
|
||||
|
||||
# Monitor the output file for "OK" or "ERROR"
|
||||
while ! grep -qe "OK" -e "ERROR" "$tmpfile"; do
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Kill the `cat` process after capturing the response
|
||||
kill $CAT_PID
|
||||
wait $CAT_PID 2>/dev/null
|
||||
|
||||
# Display the response
|
||||
cat "$tmpfile" | while IFS= read -r line; do
|
||||
echo -e "\033[0;32m$line\033[0m"
|
||||
done
|
||||
|
||||
# Clean up
|
||||
rm "$tmpfile"
|
||||
}
|
||||
|
||||
# Prepare the device for communication
|
||||
setup_device
|
||||
|
||||
# Check if an AT command is provided as an argument
|
||||
if [ $# -gt 0 ]; then
|
||||
# Concatenate all arguments to handle commands with spaces and/or quotes correctly
|
||||
FULL_CMD="$*"
|
||||
send_at_command "$FULL_CMD"
|
||||
else
|
||||
echo -e "\033[0;36mType 'exit' to end the session.\033[0m"
|
||||
while true; do
|
||||
echo -en "\033[0;36mEnter AT Command: \033[0m"
|
||||
read user_input
|
||||
|
||||
if [[ "$user_input" == "exit" ]]; then
|
||||
echo -e "\033[0;32mExiting...\033[0m"
|
||||
break
|
||||
fi
|
||||
|
||||
send_at_command "$user_input"
|
||||
done
|
||||
fi
|
||||
4
Belowx65Toolkit/socat-at-bridge/killsmd7bridge
Normal file
4
Belowx65Toolkit/socat-at-bridge/killsmd7bridge
Normal file
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Look for the process by its command and kill it so socat can have smd7 instead
|
||||
pkill -f "/usr/bin/port_bridge smd7 at_usb2 1"
|
||||
BIN
Belowx65Toolkit/socat-at-bridge/socat-armel-static
Normal file
BIN
Belowx65Toolkit/socat-at-bridge/socat-armel-static
Normal file
Binary file not shown.
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Kill port_bridge process on boot
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usrdata/socat-at-bridge/killsmd7bridge
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Read from /dev/ttyIN and write to smd11
|
||||
BindsTo=socat-smd11.service
|
||||
After=socat-smd11.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash -c "/bin/cat /dev/ttyIN > /dev/smd11"
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
StandardInput=tty-force
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Read from /dev/smd11 and write to ttyIN
|
||||
BindsTo=socat-smd11.service
|
||||
After=socat-smd11.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash -c "/bin/cat /dev/smd11 > /dev/ttyIN"
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
StandardInput=tty-force
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Socat Serial Emulation for smd11
|
||||
After=ql-netd.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usrdata/socat-at-bridge/socat-armel-static -d -d pty,link=/dev/ttyIN,raw,echo=0,group=20,perm=660 pty,link=/dev/ttyOUT,raw,echo=1,group=20,perm=660
|
||||
# Add a delay to prevent the clients from starting too early
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Read from /dev/ttyIN2 and write to smd7
|
||||
BindsTo=socat-smd7.service
|
||||
After=socat-smd7.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash -c "/bin/cat /dev/ttyIN2 > /dev/smd7"
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
StandardInput=tty-force
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Read from /dev/smd7 and write to ttyIN2
|
||||
BindsTo=socat-smd7.service
|
||||
After=socat-smd7.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/bin/bash -c "/bin/cat /dev/smd7 > /dev/ttyIN2"
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
StandardInput=tty-force
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Socat Serial Emulation for smd7
|
||||
After=ql-netd.service
|
||||
|
||||
[Service]
|
||||
ExecStart=/usrdata/socat-at-bridge/socat-armel-static -d -d pty,link=/dev/ttyIN2,raw,echo=0,group=20,perm=660 pty,link=/dev/ttyOUT2,raw,echo=1,group=20,perm=660
|
||||
# Add a delay to prevent the clients from starting too early
|
||||
ExecStartPost=/bin/sleep 2s
|
||||
Restart=always
|
||||
RestartSec=1s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
Belowx65Toolkit/sshd/.rev
Normal file
1
Belowx65Toolkit/sshd/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
17
Belowx65Toolkit/sshd/sshd.service
Normal file
17
Belowx65Toolkit/sshd/sshd.service
Normal file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=OpenBSD Secure Shell server
|
||||
Documentation=man:sshd(8) man:sshd_config(5)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
PIDFile=/opt/var/run/sshd.pid
|
||||
ExecStartPre=/opt/sbin/sshd -t
|
||||
ExecStart=/opt/sbin/sshd -D
|
||||
ExecReload=/bin/kill -HUP $MAINPID
|
||||
KillMode=process
|
||||
Restart=on-failure
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Alias=sshd.service
|
||||
1
Belowx65Toolkit/tailscale/.rev
Normal file
1
Belowx65Toolkit/tailscale/.rev
Normal file
@@ -0,0 +1 @@
|
||||
2
|
||||
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Trigger the Tailscale Web UI
|
||||
After=tailscaled.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/bin/systemctl start tailscale-webui
|
||||
RemainAfterExit=yes
|
||||
12
Belowx65Toolkit/tailscale/systemd/tailscale-webui.service
Normal file
12
Belowx65Toolkit/tailscale/systemd/tailscale-webui.service
Normal file
@@ -0,0 +1,12 @@
|
||||
Description=Tailscale Web Interface
|
||||
After=tailscaled.service
|
||||
Requires=tailscaled.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStartPre=/bin/sleep 5
|
||||
ExecStart=/usrdata/tailscale/tailscale web --listen 0.0.0.0:8088
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
8
Belowx65Toolkit/tailscale/systemd/tailscaled.defaults
Normal file
8
Belowx65Toolkit/tailscale/systemd/tailscaled.defaults
Normal file
@@ -0,0 +1,8 @@
|
||||
# Set the port to listen on for incoming VPN packets.
|
||||
# Remote nodes will automatically be informed about the new port number,
|
||||
# but you might want to configure this in order to set external firewall
|
||||
# settings.
|
||||
PORT="41641"
|
||||
|
||||
# Extra flags you might want to pass to tailscaled.
|
||||
FLAGS=""
|
||||
16
Belowx65Toolkit/tailscale/systemd/tailscaled.service
Normal file
16
Belowx65Toolkit/tailscale/systemd/tailscaled.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Tailscale node agent
|
||||
Documentation=https://tailscale.com/kb/
|
||||
Wants=network-pre.target
|
||||
After=network-pre.target NetworkManager.service systemd-resolved.service
|
||||
|
||||
[Service]
|
||||
EnvironmentFile=/usrdata/tailscale/systemd/tailscaled.defaults
|
||||
ExecStartPre=/usrdata/tailscale/tailscaled --cleanup
|
||||
ExecStart=/usrdata/tailscale/tailscaled --statedir=/usrdata/tailscale/ --port=${PORT} $FLAGS
|
||||
ExecStopPost=/usrdata/tailscale/tailscaled --cleanup
|
||||
Restart=on-failure
|
||||
Type=notify
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user