Merge pull request #2012 from RaspAP/fix/wifi-security-open

Fix: Use SECURITY_OPEN for evaluating network protocol
This commit is contained in:
Bill Zimmerman
2025-11-28 10:27:07 +01:00
committed by GitHub
5 changed files with 345 additions and 148 deletions

120
includes/configure_client.php Executable file → Normal file
View File

@@ -3,7 +3,7 @@
use RaspAP\Networking\Hotspot\WiFiManager; use RaspAP\Networking\Hotspot\WiFiManager;
/** /**
* * WiFi client configuration page handler
* *
*/ */
function DisplayWPAConfig() function DisplayWPAConfig()
@@ -16,17 +16,15 @@ function DisplayWPAConfig()
$wifi->knownWifiStations($networks); $wifi->knownWifiStations($networks);
$wifi->setKnownStationsWPA($networks); $wifi->setKnownStationsWPA($networks);
$iface = escapeshellarg($_SESSION['wifi_client_interface']); $clientInterface = $_SESSION['wifi_client_interface'];
if (isset($_POST['connect'])) { if (isset($_POST['connect'])) {
$netid = intval($_POST['connect']); $netid = intval($_POST['connect']);
$cmd = "sudo wpa_cli -i $iface select_network $netid";
$return = shell_exec($cmd); if ($wifi->connectToNetwork($clientInterface, $netid)) {
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'); $status->addMessage('New network selected', 'success');
} else {
$status->addMessage('WPA command line client returned failure. Check your adapter.', 'danger');
} }
} elseif (isset($_POST['wpa_reinit'])) { } elseif (isset($_POST['wpa_reinit'])) {
$status->addMessage('Attempting to reinitialize wpa_supplicant', 'warning'); $status->addMessage('Attempting to reinitialize wpa_supplicant', 'warning');
@@ -34,120 +32,52 @@ function DisplayWPAConfig()
$result = $wifi->reinitializeWPA($force_remove); $result = $wifi->reinitializeWPA($force_remove);
} elseif (isset($_POST['client_settings'])) { } elseif (isset($_POST['client_settings'])) {
$tmp_networks = $networks; $tmp_networks = $networks;
if ($wpa_file = fopen('/tmp/wifidata', 'w')) {
fwrite($wpa_file, 'ctrl_interface=DIR=' . RASPI_WPA_CTRL_INTERFACE . ' GROUP=netdev' . PHP_EOL);
fwrite($wpa_file, 'update_config=1' . PHP_EOL);
foreach (array_keys($_POST) as $post) { foreach (array_keys($_POST) as $post) {
if (preg_match('/delete(\d+)/', $post, $post_match)) { if (preg_match('/delete(\d+)/', $post, $post_match)) {
$network = $tmp_networks[$_POST['ssid' . $post_match[1]]]; $network = $tmp_networks[$_POST['ssid' . $post_match[1]]];
$netid = $network['index']; $netid = $network['index'];
exec('sudo wpa_cli -i ' . $iface . ' disconnect ' . $netid); $wifi->deleteNetwork($clientInterface, $netid);
exec('sudo wpa_cli -i ' . $iface . ' remove_network ' . $netid);
unset($tmp_networks[$_POST['ssid' . $post_match[1]]]); unset($tmp_networks[$_POST['ssid' . $post_match[1]]]);
} elseif (preg_match('/disconnect(\d+)/', $post, $post_match)) {
$network = $tmp_networks[$_POST['ssid' . $post_match[1]]];
$netid = $network['index'];
$wifi->disconnectNetwork($clientInterface, $netid);
} elseif (preg_match('/update(\d+)/', $post, $post_match)) { } elseif (preg_match('/update(\d+)/', $post, $post_match)) {
// NB, multiple protocols are separated with a forward slash ('/') // NB, multiple protocols are separated with a forward slash ('/')
$protocol = $_POST['protocol' . $post_match[1]] === $wifi::SECURITY_OPEN ? $wifi::SECURITY_OPEN : 'WPA';
$tmp_networks[$_POST['ssid' . $post_match[1]]] = array( $tmp_networks[$_POST['ssid' . $post_match[1]]] = array(
'protocol' => ( $_POST['protocol' . $post_match[1]] === 'Open' ? 'Open' : 'WPA' ), 'protocol' => $protocol,
'passphrase' => $_POST['passphrase' . $post_match[1]], 'passphrase' => $_POST['passphrase' . $post_match[1]] ?? '',
'configured' => true 'configured' => true
); );
if (array_key_exists('priority' . $post_match[1], $_POST)) { if (array_key_exists('priority' . $post_match[1], $_POST)) {
$tmp_networks[$_POST['ssid' . $post_match[1]]]['priority'] = $_POST['priority' . $post_match[1]]; $tmp_networks[$_POST['ssid' . $post_match[1]]]['priority'] = $_POST['priority' . $post_match[1]];
} }
$network = $tmp_networks[$_POST['ssid' . $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]].'"'); $ssid = $_POST['ssid' . $post_match[1]];
$netid = trim(shell_exec("sudo wpa_cli -i $iface add_network")); $passphrase = $_POST['passphrase' . $post_match[1]] ?? '';
if (isset($netid)) {
$commands = [ $netid = $wifi->updateNetwork($clientInterface, $ssid, $passphrase, $protocol);
"sudo wpa_cli -i $iface set_network $netid ssid $ssid", if ($netid === null) {
"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'); $status->addMessage('Unable to add network with WPA command line client', 'warning');
} }
} }
} }
$ok = true; $result = $wifi->writeWpaSupplicant($tmp_networks, $clientInterface);
foreach ($tmp_networks as $ssid => $network) {
if ($network['protocol'] === $wifi::SECURITY_OPEN) {
fwrite($wpa_file, "network={".PHP_EOL);
fwrite($wpa_file, "\tssid=\"".$ssid."\"".PHP_EOL);
fwrite($wpa_file, "\tkey_mgmt=NONE".PHP_EOL);
fwrite($wpa_file, "\tscan_ssid=1".PHP_EOL);
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, "}".PHP_EOL);
} else {
if (strlen($network['passphrase']) >=8 && strlen($network['passphrase']) <= 63) {
unset($wpa_passphrase);
unset($line);
exec('wpa_passphrase '. $wifi->ssid2utf8( escapeshellarg($ssid) ) . ' ' . escapeshellarg($network['passphrase']), $wpa_passphrase);
foreach ($wpa_passphrase as $line) {
if (preg_match('/^\s*}\s*$/', $line)) {
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, $line.PHP_EOL);
} else {
if ( preg_match('/\\\\x[0-9A-Fa-f]{2}/',$ssid) && strpos($line, "ssid=\"") !== false ) {
fwrite($wpa_file, "\tssid=P\"".$ssid."\"".PHP_EOL);
} else {
fwrite($wpa_file, $line.PHP_EOL);
}
}
}
} elseif (strlen($network['passphrase']) == 0 && strlen($network['passkey']) == 64) {
$line = "\tpsk=" . $network['passkey'];
fwrite($wpa_file, "network={".PHP_EOL);
fwrite($wpa_file, "\tssid=\"".$ssid."\"".PHP_EOL);
fwrite($wpa_file, $line.PHP_EOL);
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, "}".PHP_EOL);
} else {
$status->addMessage('WPA passphrase must be between 8 and 63 characters', 'danger');
$ok = false;
}
}
}
if ($ok) { if ($result['success']) {
system('sudo cp /tmp/wifidata ' . RASPI_WPA_SUPPLICANT_CONFIG, $returnval); $status->addMessage($result['message'], 'success');
if ($returnval == 0) {
exec('sudo wpa_cli -i ' . $_SESSION['wifi_client_interface'] . ' reconfigure', $reconfigure_out, $reconfigure_return);
if ($reconfigure_return == 0) {
$status->addMessage('Wifi settings updated successfully', 'success');
$networks = $tmp_networks; $networks = $tmp_networks;
} else { } else {
$status->addMessage('Wifi settings updated but cannot restart (cannot execute "wpa_cli reconfigure")', 'danger'); $status->addMessage($result['message'], 'danger');
}
} else {
$status->addMessage('Wifi settings failed to be updated', 'danger');
}
}
} else {
$status->addMessage('Failed to update wifi settings', 'danger');
} }
} }
$clientInterface = $_SESSION['wifi_client_interface']; $ifaceStatus = $wifi->getInterfaceStatus($clientInterface);
exec('ip a show '.$clientInterface, $stdoutIp);
$stdoutIpAllLinesGlued = implode(" ", $stdoutIp);
$stdoutIpWRepeatedSpaces = preg_replace('/\s\s+/', ' ', $stdoutIpAllLinesGlued);
preg_match('/state (UP|DOWN)/i', $stdoutIpWRepeatedSpaces, $matchesState) || $matchesState[1] = 'unknown';
$ifaceStatus = strtolower($matchesState[1]) ? "up" : "down";
echo renderTemplate("configure_client", compact("status", "clientInterface", "ifaceStatus")); echo renderTemplate("configure_client", compact("status", "clientInterface", "ifaceStatus"));
} }

View File

@@ -112,6 +112,9 @@ function getProviderValue($id, $key)
if (!isset($obj['providers']) || !is_array($obj['providers'])) { if (!isset($obj['providers']) || !is_array($obj['providers'])) {
return false; return false;
} }
if ($id === null || !is_numeric($id)) {
return false;
}
$id--; $id--;
if (!isset($obj['providers'][$id]) || !is_array($obj['providers'][$id])) { if (!isset($obj['providers'][$id]) || !is_array($obj['providers'][$id])) {
return false; return false;

View File

@@ -9,14 +9,16 @@ www-data ALL=(ALL) NOPASSWD:/sbin/wpa_supplicant -i [a-zA-Z0-9]* -c /etc/wpa_sup
www-data ALL=(ALL) NOPASSWD:/bin/rm /var/run/wpa_supplicant/[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_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]* scan
www-data ALL=(ALL) NOPASSWD:/sbin/wpa_cli -i [a-zA-Z0-9]* status
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]* 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]* 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 [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 [a-zA-Z0-9]* 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]* 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]* 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]* 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:/sbin/wpa_cli -i [a-zA-Z0-9]* remove_network [0-9]
www-data ALL=(ALL) NOPASSWD:/bin/rm -f /var/run/wpa_supplicant/wlan[0-9]
www-data ALL=(ALL) NOPASSWD:/bin/cp /tmp/hostapddata /etc/hostapd/hostapd.conf 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 start hostapd.service
www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop hostapd.service www-data ALL=(ALL) NOPASSWD:/bin/systemctl stop hostapd.service

View File

@@ -49,7 +49,7 @@ class WiFiManager
break; break;
case 'key_mgmt': case 'key_mgmt':
if (! array_key_exists('passphrase', $network) && $lineArr[1] === 'NONE') { if (! array_key_exists('passphrase', $network) && $lineArr[1] === 'NONE') {
$network['protocol'] = 'Open'; $network['protocol'] = self::SECURITY_OPEN;
} }
break; break;
case 'priority': case 'priority':
@@ -82,27 +82,27 @@ class WiFiManager
$cacheKey, $cacheKey,
function () use ($iface) { function () use ($iface) {
$stdout = shell_exec("sudo iw dev $iface scan"); $stdout = shell_exec("sudo iw dev $iface scan");
sleep(1);
if ($stdout === null) {
return [];
}
return preg_split("/\n/", $stdout); return preg_split("/\n/", $stdout);
} }
); );
// exclude the AP from nearby networks
exec('sed -rn "s/ssid=(.*)\s*$/\1/p" ' . escapeshellarg(RASPI_HOSTAPD_CONFIG), $ap_ssid);
$ap_ssid = $ap_ssid[0] ?? '';
// determine the next index that follows the indexes of the known networks // determine the next index that follows the indexes of the known networks
$index = -1; $index = 0;
if (!empty($networks)) { if (!empty($networks)) {
foreach ($networks as $network) { foreach ($networks as $network) {
if (isset($network['index']) && ($network['index'] > $index)) { if (isset($network['index']) && is_numeric($network['index']) && ($network['index'] > $index)) {
$index = $network['index']; $index = (int)$network['index'];
} }
} }
} }
$index++; $index++;
$current = []; $current = [];
$commitCurrent = function () use (&$current, &$networks, &$index, $ap_ssid) { $commitCurrent = function () use (&$current, &$networks, &$index) {
if (empty($current['ssid'])) { if (empty($current['ssid'])) {
return; return;
} }
@@ -110,7 +110,7 @@ class WiFiManager
$ssid = $current['ssid']; $ssid = $current['ssid'];
// unprintable 7bit ASCII control codes, delete or quotes -> ignore network // unprintable 7bit ASCII control codes, delete or quotes -> ignore network
if ($ssid === $ap_ssid || preg_match('/[\x00-\x1f\x7f\'`\´"]/', $ssid)) { if (preg_match('/[\x00-\x1f\x7f\'`\´"]/', $ssid)) {
return; return;
} }
@@ -136,7 +136,7 @@ class WiFiManager
'RSSI' => $rssi, 'RSSI' => $rssi,
'index' => $index 'index' => $index
]; ];
++$index; $index++; // increment for next new network
} }
}; };
@@ -177,20 +177,50 @@ class WiFiManager
} }
$commitCurrent(); $commitCurrent();
} }
/** /**
* * Check if networks are connected via wpa_cli status
* NB: iwconfig shows the last associated SSID even when connection is inactive
*/ */
public function connectedWifiStations(&$networks) public function connectedWifiStations(&$networks)
{ {
exec('iwconfig ' .$_SESSION['wifi_client_interface'], $iwconfig_return); $wpa_state = null;
foreach ($iwconfig_return as $line) { $connected_ssid = null;
if (preg_match('/ESSID:\"([^"]+)\"/i', $line, $iwconfig_ssid)) { $iface = $_SESSION['wifi_client_interface'];
$ssid=hexSequence2lower($iwconfig_ssid[1]);
$networks[$ssid]['connected'] = true; $cmd = "sudo wpa_cli -i $iface status";
//$check=detectCaptivePortal($_SESSION['wifi_client_interface']); $status_output = shell_exec($cmd);
$networks[$ssid]["portal-url"]=$check["URL"];
if ($status_output === null || empty($status_output)) {
error_log("WiFiManager::connectedWifiStations: wpa_cli command failed or returned no output");
return;
} }
$lines = explode("\n", trim($status_output));
foreach ($lines as $line) {
$line = trim($line);
if (preg_match('/^wpa_state=(.+)$/', $line, $matches)) {
$wpa_state = trim($matches[1]);
}
if (preg_match('/^ssid=(.+)$/', $line, $matches)) {
$connected_ssid = trim($matches[1]);
}
}
if ($wpa_state === 'COMPLETED' && !empty($connected_ssid)) {
$ssid = hexSequence2lower($connected_ssid);
// check if this SSID exists in networks array
if (array_key_exists($ssid, $networks)) {
$networks[$ssid]['connected'] = true;
} else {
error_log("WiFiManager::connectedWifiStations: SSID '$ssid' not found. SSIDs: " . implode(', ', array_keys($networks)));
}
// captive portal detection
// $check = detectCaptivePortal($iface);
// if (isset($check["URL"])) {
// $networks[$ssid]["portal-url"] = $check["URL"];
// }
} }
} }
@@ -255,8 +285,11 @@ class WiFiManager
{ {
$iface = $_SESSION['wifi_client_interface']; $iface = $_SESSION['wifi_client_interface'];
if ($force == true) { if ($force == true) {
$cmd = "sudo /sbin/wpa_supplicant -i $unescapedIface -c /etc/wpa_supplicant/wpa_supplicant.conf -B 2>&1"; $cmd = "sudo rm -f /var/run/wpa_supplicant/" . $iface;
$result = shell_exec($cmd); $result = shell_exec($cmd);
$cmd = "sudo /sbin/wpa_supplicant -i $iface -c /etc/wpa_supplicant/wpa_supplicant.conf -B 2>&1";
$result = shell_exec($cmd);
sleep(2);
} }
$cmd = "sudo wpa_cli -i $iface reconfigure"; $cmd = "sudo wpa_cli -i $iface reconfigure";
$result = shell_exec($cmd); $result = shell_exec($cmd);
@@ -425,7 +458,7 @@ class WiFiManager
"sudo wpa_cli -i $iface set_network $netid ssid $ssid", "sudo wpa_cli -i $iface set_network $netid ssid $ssid",
]; ];
if (strtolower($protocol) === 'open') { if ($protocol === self::SECURITY_OPEN) {
$commands[] = "sudo wpa_cli -i $iface set_network $netid key_mgmt NONE"; $commands[] = "sudo wpa_cli -i $iface set_network $netid key_mgmt NONE";
} else { } else {
$commands[] = "sudo wpa_cli -i $iface set_network $netid psk $psk"; $commands[] = "sudo wpa_cli -i $iface set_network $netid psk $psk";
@@ -464,7 +497,7 @@ class WiFiManager
foreach ($output as $line) { foreach ($output as $line) {
$columns = preg_split('/\t/', $line); $columns = preg_split('/\t/', $line);
if (count($columns) >= 2 && trim($columns[1]) === trim($ssid)) { if (count($columns) >= 2 && trim($columns[1]) === trim($ssid)) {
return (int)$columns[0]; return (int)$columns[0]; // return network ID
} }
} }
return null; return null;
@@ -519,5 +552,211 @@ CONF;
} }
} }
/**
* Gets the operational status of a network interface
*
* @param string $interface network interface name
* @return string returns up, down, or unknown
*/
public function getInterfaceStatus(string $interface): string
{
exec('ip a show ' . escapeshellarg($interface), $output);
$outputGlued = implode(" ", $output);
$outputNormalized = preg_replace('/\s\s+/', ' ', $outputGlued);
if (preg_match('/state (UP|DOWN)/i', $outputNormalized, $matches)) {
return strtolower($matches[1]);
} }
return 'unknown';
}
/**
* Connects to a network using wpa_cli
*
* @param string $interface network interface name
* @param int $netid network ID to connect to
* @return bool true on success, false on failure
*/
public function connectToNetwork(string $interface, int $netid): bool
{
$iface = escapeshellarg($interface);
$cmd = "sudo wpa_cli -i $iface select_network $netid";
$selectResult = shell_exec($cmd);
if ($selectResult === null || trim($selectResult) === "FAIL") {
return false;
}
sleep(3);
$cmd = "sudo wpa_cli -i $iface reassociate";
$reassociateResult = shell_exec($cmd);
if ($reassociateResult !== null) {
$trimmed = trim($reassociateResult);
if ($trimmed === "FAIL") {
return false;
}
}
return true;
}
/**
* Deletes a network from wpa_cli
*
* @param string $interface network interface name
* @param int $netid network ID to delete
* @return void
*/
public function deleteNetwork(string $interface, int $netid): void
{
$iface = escapeshellarg($interface);
exec("sudo wpa_cli -i $iface disconnect $netid");
exec("sudo wpa_cli -i $iface remove_network $netid");
}
/**
* Disconnects from a network using wpa_cli
*
* @param string $interface network interface name
* @param int $netid network ID to disconnect from
* @return void
*/
public function disconnectNetwork(string $interface, int $netid): void
{
$iface = escapeshellarg($interface);
exec("sudo wpa_cli -i $iface disconnect $netid");
exec("sudo wpa_cli -i $iface remove_network $netid");
sleep(2);
}
/**
* Updates/adds a network via wpa_cli
*
* @param string $interface network interface name
* @param string $ssid network SSID
* @param string $passphrase network passphrase
* @param string $protocol security protocol (OPEN or WPA)
* @return int|null network ID on success, null on failure
*/
public function updateNetwork(string $interface, string $ssid, string $passphrase, string $protocol = 'WPA'): ?int
{
$iface = escapeshellarg($interface);
$escapedSsid = escapeshellarg('"' . $ssid . '"');
$netid = shell_exec("sudo wpa_cli -i $iface add_network");
if ($netid === null || !is_numeric(trim($netid))) {
return null;
}
$netid = trim($netid);
$commands = [
"sudo wpa_cli -i $iface set_network $netid ssid $escapedSsid"
];
if ($protocol === self::SECURITY_OPEN) {
$commands[] = "sudo wpa_cli -i $iface set_network $netid key_mgmt NONE";
} else {
$escapedPsk = escapeshellarg('"' . $passphrase . '"');
$commands[] = "sudo wpa_cli -i $iface set_network $netid psk $escapedPsk";
}
$commands[] = "sudo wpa_cli -i $iface enable_network $netid";
foreach ($commands as $cmd) {
exec($cmd);
}
return (int)$netid;
}
/**
* Writes a wpa_supplicant configuration and applies it
*
* @param array $networks array of network configurations
* @param string $interface the network interface name
* @return array Array with 'success' (bool) and 'message' (string)
*/
public function writeWpaSupplicant(array $networks, string $interface): array
{
$wpa_file = fopen('/tmp/wifidata', 'w');
if (!$wpa_file) {
return ['success' => false, 'message' => 'Failed to update wifi settings'];
}
fwrite($wpa_file, 'ctrl_interface=DIR=' . RASPI_WPA_CTRL_INTERFACE . ' GROUP=netdev' . PHP_EOL);
fwrite($wpa_file, 'update_config=1' . PHP_EOL);
$ok = true;
foreach ($networks as $ssid => $network) {
if ($network['protocol'] === self::SECURITY_OPEN) {
fwrite($wpa_file, "network={".PHP_EOL);
fwrite($wpa_file, "\tssid=\"".$ssid."\"".PHP_EOL);
fwrite($wpa_file, "\tkey_mgmt=NONE".PHP_EOL);
fwrite($wpa_file, "\tscan_ssid=1".PHP_EOL);
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, "}".PHP_EOL);
} else {
if (strlen($network['passphrase']) >= 8 && strlen($network['passphrase']) <= 63) {
unset($wpa_passphrase);
unset($line);
exec('wpa_passphrase '. $this->ssid2utf8(escapeshellarg($ssid)) . ' ' . escapeshellarg($network['passphrase']), $wpa_passphrase);
foreach ($wpa_passphrase as $line) {
if (preg_match('/^\s*}\s*$/', $line)) {
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, $line.PHP_EOL);
} else {
if (preg_match('/\\\\x[0-9A-Fa-f]{2}/', $ssid) && strpos($line, "ssid=\"") !== false) {
fwrite($wpa_file, "\tssid=P\"".$ssid."\"".PHP_EOL);
} else {
fwrite($wpa_file, $line.PHP_EOL);
}
}
}
} elseif (strlen($network['passphrase']) == 0 && strlen($network['passkey']) == 64) {
$line = "\tpsk=" . $network['passkey'];
fwrite($wpa_file, "network={".PHP_EOL);
fwrite($wpa_file, "\tssid=\"".$ssid."\"".PHP_EOL);
fwrite($wpa_file, $line.PHP_EOL);
if (array_key_exists('priority', $network)) {
fwrite($wpa_file, "\tpriority=".$network['priority'].PHP_EOL);
}
fwrite($wpa_file, "}".PHP_EOL);
} else {
$ok = false;
fclose($wpa_file);
return ['success' => false, 'message' => 'WPA passphrase must be between 8 and 63 characters'];
}
}
}
fclose($wpa_file);
if ($ok) {
system('sudo cp /tmp/wifidata ' . RASPI_WPA_SUPPLICANT_CONFIG, $returnval);
if ($returnval == 0) {
exec('sudo wpa_cli -i ' . escapeshellarg($interface) . ' reconfigure', $reconfigure_out, $reconfigure_return);
if ($reconfigure_return == 0) {
return ['success' => true, 'message' => 'Wifi settings updated successfully'];
} else {
return ['success' => false, 'message' => 'Wifi settings updated but cannot restart (cannot execute "wpa_cli reconfigure")'];
}
} else {
return ['success' => false, 'message' => 'Wifi settings failed to be updated'];
}
}
return ['success' => false, 'message' => 'Unknown error'];
}
}

View File

@@ -3,6 +3,25 @@
use RaspAP\Networking\Hotspot\WiFiManager; use RaspAP\Networking\Hotspot\WiFiManager;
$wifi = new WiFiManager(); $wifi = new WiFiManager();
// fix: re-apply locale settings in this template context
if (!empty($_SESSION['locale'])) {
putenv("LANG=" . $_SESSION['locale']);
setlocale(LC_ALL, $_SESSION['locale']);
bindtextdomain('messages', realpath(__DIR__ . '/../../locale'));
bind_textdomain_codeset('messages', 'UTF-8');
textdomain('messages');
}
// set defaults
$network = $network ?? [];
$network['ssid'] = $network['ssid'] ?? '';
$network['ssidutf8'] = $network['ssidutf8'] ?? $network['ssid'];
$network['configured'] = $network['configured'] ?? false;
$network['connected'] = $network['connected'] ?? false;
$network['visible'] = $network['visible'] ?? false;
$network['channel'] = $network['channel'] ?? '';
$network['protocol'] = $network['protocol'] ?? $wifi::SECURITY_OPEN;
$network['passphrase'] = $network['passphrase'] ?? '';
?> ?>
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
@@ -57,7 +76,7 @@ $wifi = new WiFiManager();
<div class="mb-3"> <div class="mb-3">
<div class="info-item-wifi mb-2"><?php echo _("Passphrase"); ?></div> <div class="info-item-wifi mb-2"><?php echo _("Passphrase"); ?></div>
<div class="input-group"> <div class="input-group">
<?php if ($network['protocol'] === 'Open') { ?> <?php if ($network['protocol'] === $wifi::SECURITY_OPEN) { ?>
<input type="password" disabled class="form-control" aria-describedby="passphrase" name="passphrase<?php echo $index ?>" value="" /> <input type="password" disabled class="form-control" aria-describedby="passphrase" name="passphrase<?php echo $index ?>" value="" />
<?php } else { ?> <?php } else { ?>
<input type="password" class="form-control" aria-describedby="passphrase" name="passphrase<?php echo $index ?>" value="<?php echo htmlspecialchars($network['passphrase']); ?>" data-bs-target="#update<?php echo $index ?>" data-colors="#ffd0d0,#d0ffd0"> <input type="password" class="form-control" aria-describedby="passphrase" name="passphrase<?php echo $index ?>" value="<?php echo htmlspecialchars($network['passphrase']); ?>" data-bs-target="#update<?php echo $index ?>" data-colors="#ffd0d0,#d0ffd0">
@@ -69,7 +88,11 @@ $wifi = new WiFiManager();
<div class="btn-group btn-block d-flex"> <div class="btn-group btn-block d-flex">
<?php if ($network['configured']) { ?> <?php if ($network['configured']) { ?>
<input type="submit" class="btn btn-warning" value="<?php echo _("Update"); ?>" id="update<?php echo $index ?>" name="update<?php echo $index ?>"<?php echo ($network['protocol'] === 'Open' ? ' disabled' : '')?> data-bs-toggle="modal" data-bs-target="#configureClientModal" /> <input type="submit" class="btn btn-warning" value="<?php echo _("Update"); ?>" id="update<?php echo $index ?>" name="update<?php echo $index ?>"<?php echo ($network['protocol'] === 'Open' ? ' disabled' : '')?> data-bs-toggle="modal" data-bs-target="#configureClientModal" />
<?php if ($network['connected']) { ?>
<button type="submit" class="btn btn-info" value="<?php echo $index?>" name="disconnect<?php echo $index ?>"><?php echo _("Disconnect"); ?></button>
<?php } else { ?>
<button type="submit" class="btn btn-info" value="<?php echo $index?>" name="connect"><?php echo _("Connect"); ?></button> <button type="submit" class="btn btn-info" value="<?php echo $index?>" name="connect"><?php echo _("Connect"); ?></button>
<?php } ?>
<?php } else { ?> <?php } else { ?>
<input type="submit" class="btn btn-info" value="<?php echo _("Add"); ?>" id="update<?php echo $index ?>" name="update<?php echo $index ?>" data-bs-toggle="modal" data-bs-target="#configureClientModal" /> <input type="submit" class="btn btn-info" value="<?php echo _("Add"); ?>" id="update<?php echo $index ?>" name="update<?php echo $index ?>" data-bs-toggle="modal" data-bs-target="#configureClientModal" />
<?php } ?> <?php } ?>