diff --git a/app/css/all.css b/app/css/all.css index 6553afa5..3a095198 100644 --- a/app/css/all.css +++ b/app/css/all.css @@ -110,10 +110,31 @@ License: GNU General Public License v3.0 margin-bottom: 0.5em; } -.loading-spinner { - background: url("../../app/img/loading-spinner.gif") no-repeat scroll center center transparent; - min-height: 450px; +#wifiClientContent #wpaConf { + min-height: calc(100vh / 3); +} + +.loading-spinner::before { + position: absolute; + top: 0; + left: 0; width: 100%; + height: calc(100vh / 4); + display: flex; + justify-content: center; + align-items: center; + color: #858796; + content: "\f1ce"; /* Unicode for the circle-notch icon */ + font-family: "Font Awesome 5 Free"; + font-weight: 900; /* Adjust as needed */ + font-size: 54px; /* Adjust icon size as needed */ + animation: spin 1.2s linear infinite; + width: 100%; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } } @media (min-width: 576px) { diff --git a/app/img/loading-spinner.gif b/app/img/loading-spinner.gif deleted file mode 100644 index f7e0378a..00000000 Binary files a/app/img/loading-spinner.gif and /dev/null differ diff --git a/app/img/no-trace-200x200.png b/app/img/no-trace-200x200.png deleted file mode 100644 index ab1b40e4..00000000 Binary files a/app/img/no-trace-200x200.png and /dev/null differ diff --git a/includes/configure_client.php b/includes/configure_client.php index 41da0716..d390b8c5 100755 --- a/includes/configure_client.php +++ b/includes/configure_client.php @@ -13,18 +13,24 @@ function DisplayWPAConfig() getWifiInterface(); knownWifiStations($networks); + setKnownStationsWPA($networks); + + $iface = escapeshellarg($_SESSION['wifi_client_interface']); if (isset($_POST['connect'])) { - $result = 0; - $iface = escapeshellarg($_SESSION['wifi_client_interface']); $netid = intval($_POST['connect']); - exec('sudo wpa_cli -i ' . $iface . ' select_network ' . $netid); - $status->addMessage('New network selected', 'success'); + $cmd = "sudo wpa_cli -i $iface select_network $netid"; + $return = shell_exec($cmd); + sleep(2); + if (trim($return) == "FAIL") { + $status->addMessage('WPA command line client returned failure. Check your adapter.', 'danger'); + } else { + $status->addMessage('New network selected', 'success'); + } } elseif (isset($_POST['wpa_reinit'])) { - $status->addMessage('Reinitializing wpa_supplicant', 'info', false); + $status->addMessage('Attempting to reinitialize wpa_supplicant', 'warning'); $force_remove = true; $result = reinitializeWPA($force_remove); - $status->addMessage($result, 'info'); } elseif (isset($_POST['client_settings'])) { $tmp_networks = $networks; if ($wpa_file = fopen('/tmp/wifidata', 'w')) { @@ -32,8 +38,14 @@ function DisplayWPAConfig() fwrite($wpa_file, 'update_config=1' . PHP_EOL); foreach (array_keys($_POST) as $post) { + if (preg_match('/delete(\d+)/', $post, $post_match)) { + $network = $tmp_networks[$_POST['ssid' . $post_match[1]]]; + $netid = $network['index']; + exec('sudo wpa_cli -i ' . $iface . ' disconnect ' . $netid); + exec('sudo wpa_cli -i ' . $iface . ' remove_network ' . $netid); unset($tmp_networks[$_POST['ssid' . $post_match[1]]]); + } elseif (preg_match('/update(\d+)/', $post, $post_match)) { // NB, multiple protocols are separated with a forward slash ('/') $tmp_networks[$_POST['ssid' . $post_match[1]]] = array( @@ -44,6 +56,22 @@ function DisplayWPAConfig() if (array_key_exists('priority' . $post_match[1], $_POST)) { $tmp_networks[$_POST['ssid' . $post_match[1]]]['priority'] = $_POST['priority' . $post_match[1]]; } + $network = $tmp_networks[$_POST['ssid' . $post_match[1]]]; + $ssid = escapeshellarg('"'.$_POST['ssid' . $post_match[1]].'"'); + $psk = escapeshellarg('"'.$_POST['passphrase' . $post_match[1]].'"'); + $netid = trim(shell_exec("sudo wpa_cli -i $iface add_network")); + if (isset($netid)) { + $commands = [ + "sudo wpa_cli -i $iface set_network $netid ssid $ssid", + "sudo wpa_cli -i $iface set_network $netid psk $psk", + "sudo wpa_cli -i $iface enable_network $netid" + ]; + foreach ($commands as $cmd) { + exec($cmd); + } + } else { + $status->addMessage('Unable to add network with WPA command line client', 'warning'); + } } } diff --git a/includes/wifi_functions.php b/includes/wifi_functions.php index 1ef0e225..2056471f 100755 --- a/includes/wifi_functions.php +++ b/includes/wifi_functions.php @@ -9,10 +9,10 @@ function knownWifiStations(&$networks) { // Find currently configured networks exec(' sudo cat ' . RASPI_WPA_SUPPLICANT_CONFIG, $known_return); - $index = 0; + //$index = 0; foreach ($known_return as $line) { if (preg_match('/network\s*=/', $line)) { - $network = array('visible' => false, 'configured' => true, 'connected' => false, 'index' => $index); + $network = array('visible' => false, 'configured' => true, 'connected' => false, 'index' => null); ++$index; } elseif (isset($network) && $network !== null) { if (preg_match('/^\s*}\s*$/', $line)) { @@ -25,6 +25,8 @@ function knownWifiStations(&$networks) $ssid = trim($lineArr[1], '"'); $ssid = str_replace('P"','',$ssid); $network['ssid'] = $ssid; + $index = getNetworkIdBySSID($ssid); + $network['index'] = $index; break; case 'psk': $network['passkey'] = trim($lineArr[1]); @@ -62,7 +64,6 @@ function nearbyWifiStations(&$networks, $cached = true) $cacheKey, function () { exec('sudo wpa_cli -i ' .$_SESSION['wifi_client_interface']. ' scan'); sleep(3); - $stdout = shell_exec('sudo wpa_cli -i ' .$_SESSION['wifi_client_interface']. ' scan_results'); return preg_split("/\n/", $stdout); } @@ -182,12 +183,14 @@ function getWifiInterface() */ function reinitializeWPA($force) { + $iface = escapeshellarg($_SESSION['wifi_client_interface']); if ($force == true) { - $cmd = escapeshellcmd("sudo /bin/rm /var/run/wpa_supplicant/".$_SESSION['wifi_client_interface']); - $result = exec($cmd); + $cmd = "sudo /bin/rm /var/run/wpa_supplicant/$iface"; + $result = shell_exec($cmd); } - $cmd = escapeshellcmd("sudo /sbin/wpa_supplicant -B -Dnl80211,wext -c/etc/wpa_supplicant/wpa_supplicant.conf -i". $_SESSION['wifi_client_interface']); + $cmd = "sudo wpa_cli -i $iface reconfigure"; $result = shell_exec($cmd); + sleep(1); return $result; } @@ -235,3 +238,82 @@ function getSignalBars($rssi) return $elem; } +/* + * Parses output of wpa_cli list_networks, compares with known networks + * from wpa_supplicant, and adds with wpa_cli if not found + * + * @param array $networks + */ +function setKnownStationsWPA($networks) +{ + $iface = escapeshellarg($_SESSION['wifi_client_interface']); + $output = shell_exec("sudo wpa_cli -i $iface list_networks"); + $lines = explode("\n", $output); + array_shift($lines); + $wpaCliNetworks = []; + + foreach ($lines as $line) { + $data = explode("\t", trim($line)); + if (!empty($data) && count($data) >= 2) { + $id = $data[0]; + $ssid = $data[1]; + $item = [ + 'id' => $id, + 'ssid' => $ssid + ]; + $wpaCliNetworks[] = $item; + } + } + foreach ($networks as $network) { + $ssid = $network['ssid']; + if (!networkExists($ssid, $wpaCliNetworks)) { + $ssid = escapeshellarg('"'.$network['ssid'].'"'); + $psk = escapeshellarg('"'.$network['passphrase'].'"'); + $netid = trim(shell_exec("sudo wpa_cli -i $iface add_network")); + if (isset($netid) && !isset($known[$netid])) { + $commands = [ + "sudo wpa_cli -i $iface set_network $netid ssid $ssid", + "sudo wpa_cli -i $iface set_network $netid psk $psk", + "sudo wpa_cli -i $iface enable_network $netid" + ]; + foreach ($commands as $cmd) { + exec($cmd); + usleep(1000); + } + } + } + } +} + +/* + * Parses wpa_cli list_networks output and returns the id + * of a corresponding network SSID + * + * @param string $ssid + * @return integer id + */ +function getNetworkIdBySSID($ssid) { + $iface = escapeshellarg($_SESSION['wifi_client_interface']); + $cmd = "sudo wpa_cli -i $iface list_networks"; + $output = []; + exec($cmd, $output); + array_shift($output); + foreach ($output as $line) { + $columns = preg_split('/\t/', $line); + if (count($columns) >= 4 && trim($columns[1]) === trim($ssid)) { + return $columns[0]; // return network ID + } + } + return null; +} + +function networkExists($ssid, $collection) +{ + foreach ($collection as $network) { + if ($network['ssid'] === $ssid) { + return true; + } + } + return false; +} + diff --git a/installers/raspap.sudoers b/installers/raspap.sudoers index 8d3d817c..99de3b1d 100644 --- a/installers/raspap.sudoers +++ b/installers/raspap.sudoers @@ -1,15 +1,21 @@ www-data ALL=(ALL) NOPASSWD:/sbin/ifdown www-data ALL=(ALL) NOPASSWD:/sbin/ifup www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wpa_supplicant/wpa_supplicant.conf -www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wpa_supplicant/wpa_supplicant-wlan[0-9].conf +www-data ALL=(ALL) NOPASSWD:/bin/cat /etc/wpa_supplicant/wpa_supplicant-[a-zA-Z0-9]*.conf www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wifidata /etc/wpa_supplicant/wpa_supplicant.conf -www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wifidata /etc/wpa_supplicant/wpa_supplicant-wlan[0-9].conf -www-data ALL=(ALL) NOPASSWD:/sbin/wpa_supplicant -B -Dnl80211 -c/etc/wpa_supplicant/wpa_supplicant.conf -iwlan[0-9] -www-data ALL=(ALL) NOPASSWD:/bin/rm /var/run/wpa_supplicant/wlan[0-9] -www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i wlan[0-9] scan_results -www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i wlan[0-9] scan -www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i wlan[0-9] reconfigure -www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i wlan[0-9] select_network [0-9]* +www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/wifidata /etc/wpa_supplicant/wpa_supplicant-wl*.conf +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_supplicant -B -Dnl80211 -c/etc/wpa_supplicant/wpa_supplicant.conf -i[a-zA-Z0-9]* +www-data ALL=(ALL) NOPASSWD:/bin/rm /var/run/wpa_supplicant/[a-zA-Z0-9]* +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* scan_results +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* scan +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* reconfigure +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* add_network +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* list_networks +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i enable_network [0-9] +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i disconnect [0-9] +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* select_network [0-9] +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* set_network [0-9] * +www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* remove_network [0-9] www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/hostapddata /etc/hostapd/hostapd.conf www-data ALL=(ALL) NOPASSWD:/bin/systemctl start hostapd.service www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop hostapd.service @@ -28,9 +34,9 @@ www-data ALL=(ALL) NOPASSWD:/bin/rm /etc/dnsmasq.d/090_*.conf www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/dhcpddata /etc/dhcpcd.conf www-data ALL=(ALL) NOPASSWD:/sbin/shutdown -h now www-data ALL=(ALL) NOPASSWD:/sbin/reboot -www-data ALL=(ALL) NOPASSWD:/sbin/ip link set wlan[0-9] down -www-data ALL=(ALL) NOPASSWD:/sbin/ip link set wlan[0-9] up -www-data ALL=(ALL) NOPASSWD:/sbin/ip -s a f label wlan[0-9] +www-data ALL=(ALL) NOPASSWD:/sbin/ip link set wl* down +www-data ALL=(ALL) NOPASSWD:/sbin/ip link set wl* up +www-data ALL=(ALL) NOPASSWD:/sbin/ip -s a f label wl* www-data ALL=(ALL) NOPASSWD:/sbin/ifup * www-data ALL=(ALL) NOPASSWD:/sbin/ifdown * www-data ALL=(ALL) NOPASSWD:/sbin/iw diff --git a/templates/configure_client.php b/templates/configure_client.php index aeca17bd..45c44265 100755 --- a/templates/configure_client.php +++ b/templates/configure_client.php @@ -24,7 +24,7 @@ -