Merge Feature/utility library (asu cidse 2025 fall) to main test - #50
Daniel-Lopez246 wants to merge 139 commits into
Conversation
removed echo lines since daemon will now mostly be called from command line also uncommented clear_internet_sessions so that shutdown will clear internet sessions
had error with session_age and resolving some of the variables as octal which would give a number outside of base error when '09' or '08' appeared changed some other stuff as well
for iptmon_rx to work properly it needs to intercept the packet before it leaves the wlan1 interface which doesn't happen from the FORWARD mangle table also some misc changes
not in use anymore and code is completely irrelevent
general debugging and making webpage easier to navigate
lots of changes
new simple generic logo added as well
after getting a better understanding of primary keys, I updated primary keys to just be user_id for the first 2 tables. Certain columns will still need to be unique such at table_index and others. But this will have to be done externally.
added "list rules" to list out iptable rules
added "globalfunctions.php" to increase reusability, still looking to create a global CSS file for common html formatting
…s, and deterministic cleanup with full automated test coverage
…y and consistency across scripts
- Updated variable quoting for better safety and to prevent word splitting in Cybercafe_setupFunctions.sh, Cybercafe_testbed.sh, cybercafe.sh, and run.sh. - Enhanced error logging with clearer messages and consistent formatting. - Improved command execution in shutdown_infrastructure and setup_infrastructure functions to ensure proper error handling. - Added shellcheck directives to suppress specific warnings for better code clarity. - Adjusted user prompts to use read -r for safer input handling. - Cleaned up deprecated rules and comments in iptables configurations. - Ensured consistent use of double quotes around variables to prevent issues with spaces and special characters.
…s commands and test helpers
Fixed CI Pipeline
…s commands for correct syntax
Just some bug fixes and an additional suppress
…cution wrapping full cybercafe lifecycle: preflight → build → run → status → shutdown and imdempotent behavior by skipping builds if it already exists and runs guards against duplicate starts from daemon. - Stage isolation: each stage callable independently or as full 'all' run - Logs all output to orchestrator.log for validation evidence - Targets T95 device via Termux with root access required - Fixes --rebuild flag typo in build stage warn message
…nexpectedly so replace with the proper if block.
… variable with globbing and word splitting warnings.
…read the file directly.
…o keep consistent over shellcheck style preference and readability.
…cution Stage isolation: each stage callable independently or as full 'all' run Logs all output to orchestrator.log for validation evidence Targets T95 device via Termux with root access required Fixes --rebuild flag typo in build stage warn message
…_infrastructure function
…A-9477/fix-for-demo
Added shellcheck disable comments to prevent warnings for variable expansion.
Backend is now stable for demo
There was a problem hiding this comment.
Code Review
This pull request introduces a comprehensive management system for a Cybercafe hotspot, including a session daemon, infrastructure setup scripts, and a PHP-based web interface. The review identifies critical SQL injection vulnerabilities in the frontend and several technical issues in the backend scripts, such as syntax errors, unhandled NULL database results, and inefficient command execution within loops. Additionally, the feedback recommends avoiding hardcoded interface names and refining traffic redirection rules to ensure compatibility with non-HTTP services. All provided comments point to valid bugs or improvement opportunities.
| #Calculate what entry number this will be saved under in user_data_usage for this user on this session | ||
| RESPONSE=$(sqlite3 "${DATABASE_PATH}" "SELECT MAX(session_entry_index) FROM user_data_usage WHERE user_id='${USER_ID}' AND session_number=${SESSION_NUMBER}") > /dev/null 2>> error.log | ||
| ENTRY_INDEX=$((RESPONSE + 1)) | ||
| RESPONSE=$(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND session_number='${SESSION_NUMBER}')") > /dev/null 2>> error.log |
There was a problem hiding this comment.
There is a syntax error in the SQL query due to an extra closing parenthesis ) at the end of the string. This will cause the sqlite3 command to fail.
| RESPONSE=$(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND session_number='${SESSION_NUMBER}')") > /dev/null 2>> error.log | |
| RESPONSE=$(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND session_number='${SESSION_NUMBER}'" 2>> error.log) |
| #check that username is unique | ||
| $response = $db->query("SELECT 1 FROM users WHERE username='".$username."'"); | ||
| $responseArray = $response->fetchArray(); |
There was a problem hiding this comment.
The $username variable is concatenated directly into the SQL query, which makes the application vulnerable to SQL injection. Use prepared statements to safely handle user input.
$stmt = $db->prepare("SELECT 1 FROM users WHERE username=:username");
$stmt->bindValue(':username', $username, SQLITE3_TEXT);
$response = $stmt->execute();
$responseArray = $response->fetchArray();
if($responseArray)| $db = global_createDatabaseObj(); | ||
| $response = $db->query("SELECT user_id FROM internet_sessions WHERE session_id='".$cookies['session_id']."'"); | ||
| $responseArray = $response->fetchArray(); |
There was a problem hiding this comment.
The session_id from cookies is used directly in a query without sanitization or prepared statements, leading to a SQL injection vulnerability.
$db = global_createDatabaseObj();
$stmt = $db->prepare("SELECT user_id FROM internet_sessions WHERE session_id=:session_id");
$stmt->bindValue(':session_id', $cookies['session_id'], SQLITE3_TEXT);
$response = $stmt->execute();
$responseArray = $response->fetchArray();| TOTAL_TX_DAY=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')"))) > /dev/null | ||
| TOTAL_RX_DAY=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')"))) > /dev/null | ||
| TOTAL_TX_WEEK=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')"))) > /dev/null | ||
| TOTAL_RX_WEEK=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')"))) > /dev/null | ||
| TOTAL_TX_MONTH=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')"))) > /dev/null | ||
| TOTAL_RX_MONTH=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')"))) > /dev/null |
There was a problem hiding this comment.
If the SUM function returns NULL (which happens if no rows match the criteria), the sqlite3 command will output an empty string. This causes a syntax error in Bash arithmetic expansion $((...)). Use COALESCE or IFNULL in the SQL query to ensure a numeric value is always returned.
| TOTAL_TX_DAY=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')"))) > /dev/null | |
| TOTAL_RX_DAY=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')"))) > /dev/null | |
| TOTAL_TX_WEEK=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')"))) > /dev/null | |
| TOTAL_RX_WEEK=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')"))) > /dev/null | |
| TOTAL_TX_MONTH=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_tx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')"))) > /dev/null | |
| TOTAL_RX_MONTH=$(($(sqlite3 "${DATABASE_PATH}" "SELECT SUM(interval_bytes_rx) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')"))) > /dev/null | |
| TOTAL_TX_DAY=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_tx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')") | |
| TOTAL_RX_DAY=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_rx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-1 days')") | |
| TOTAL_TX_WEEK=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_tx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')") | |
| TOTAL_RX_WEEK=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_rx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-7 days')") | |
| TOTAL_TX_MONTH=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_tx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')") | |
| TOTAL_RX_MONTH=$(sqlite3 "${DATABASE_PATH}" "SELECT COALESCE(SUM(interval_bytes_rx), 0) FROM user_data_usage WHERE user_id='${USER_ID}' AND entry_datetime>=datetime(datetime(),'localtime','-30 days')") |
| SESSION_TX=$(($(iptables -t mangle -L iptmon_tx -vxn | grep "${USER_IP}" | awk '{print $2}'))) | ||
| SESSION_RX=$(($(iptables -t mangle -L iptmon_rx -vxn | grep "${USER_IP}" | awk '{print $2}'))) |
There was a problem hiding this comment.
Executing iptables -L inside a loop for every internet session is extremely inefficient and will cause significant performance degradation as the number of sessions grows. Additionally, the grep command might match multiple lines if an IP address is a substring of another (e.g., 192.168.1.1 matching 192.168.1.10), leading to incorrect results.
| SESSION_TX=$(($(iptables -t mangle -L iptmon_tx -vxn | grep "${USER_IP}" | awk '{print $2}'))) | |
| SESSION_RX=$(($(iptables -t mangle -L iptmon_rx -vxn | grep "${USER_IP}" | awk '{print $2}'))) | |
| SESSION_TX=$(iptables -t mangle -L iptmon_tx -vxn | awk -v ip="${USER_IP}" '$0 ~ " "ip" " {print $2}') | |
| SESSION_RX=$(iptables -t mangle -L iptmon_rx -vxn | awk -v ip="${USER_IP}" '$0 ~ " "ip" " {print $2}') |
| iptables -t nat -I PREROUTING 1 -p tcp -i "${HS_INTERFACE}" \ | ||
| -m comment --comment "cybercafe-dnat" \ | ||
| -j DNAT --to-destination "${LOCAL_IP}:80" |
There was a problem hiding this comment.
This rule redirects all TCP traffic on the hotspot interface to port 80. This will break HTTPS (port 443) and any other TCP-based services. It is recommended to restrict this redirection to port 80 only.
| iptables -t nat -I PREROUTING 1 -p tcp -i "${HS_INTERFACE}" \ | |
| -m comment --comment "cybercafe-dnat" \ | |
| -j DNAT --to-destination "${LOCAL_IP}:80" | |
| iptables -t nat -I PREROUTING 1 -p tcp --dport 80 -i "${HS_INTERFACE}" \ | |
| -m comment --comment "cybercafe-dnat" \ | |
| -j DNAT --to-destination "${LOCAL_IP}:80" |
| while true; do | ||
| trap 'echo -e "$(date) Error in Cybercafe_daemon.sh: Line ${LINENO}\n" >> error.log' ERR > /dev/null 2>> error.log |
There was a problem hiding this comment.
The trap command is defined inside the while true loop, which means it is re-registered on every iteration. It should be moved outside the loop for better performance and clarity.
| while true; do | |
| trap 'echo -e "$(date) Error in Cybercafe_daemon.sh: Line ${LINENO}\n" >> error.log' ERR > /dev/null 2>> error.log | |
| trap 'echo -e "$(date) Error in Cybercafe_daemon.sh: Line ${LINENO}\n" >> error.log' ERR > /dev/null 2>> error.log | |
| while true; do |
| INDEX_LIMIT=$(($(sqlite3 "${DATABASE_PATH}" "SELECT MAX(table_index) FROM internet_sessions;")+1)) > /dev/null 2>> error.log #the maximum number of internet session entries | ||
| while [ $I -lt $INDEX_LIMIT ] |
There was a problem hiding this comment.
| HS_STATUS_PREV="$HS_STATUS" | ||
|
|
||
| # From Chris's with better probing method to grab a specific IP pattern for the hotspot | ||
| ip add show dev wlan0 | grep 192\.168\.43\. > /dev/null 2>> error.log # Does it appear the hotspot is active? |
There was a problem hiding this comment.
The network interface wlan0 is hardcoded here. It should use the $HS_INTERFACE variable defined in the configuration file to ensure consistency and portability.
| ip add show dev wlan0 | grep 192\.168\.43\. > /dev/null 2>> error.log # Does it appear the hotspot is active? | |
| ip add show dev "$HS_INTERFACE" | grep 192\.168\.43\. > /dev/null 2>> error.log # Does it appear the hotspot is active? |
No description provided.