SSL-Verifizierung als Opt-in: pro Site (UniFi) und für SMTP
- UniFiController: CURLOPT_SSL_VERIFYPEER/-HOST über neues Site-Feld ssl_verify steuerbar (Default aus, da UniFi meist self-signed); testConnection() und alle Aufrufer angepasst - sites: Checkbox in Anlegen/Bearbeiten-Modal, Spalte via Migration 0003 (Alt-Installationen tolerant über '?? 0') - Mailer: stream_context verify_peer/verify_peer_name über neues Setting smtp_verify_ssl (Checkbox im SMTP-Tab) - Sprach-Keys de/en ergänzt https://claude.ai/code/session_01KKVpVPJjrTKGoRgpJcySD4
This commit is contained in:
parent
6e19958a37
commit
968afbb212
12 changed files with 68 additions and 26 deletions
|
|
@ -31,7 +31,7 @@ if (isset($_GET['ajax_stats'])) {
|
||||||
@set_time_limit(30 + count($sites) * 20);
|
@set_time_limit(30 + count($sites) * 20);
|
||||||
foreach ($sites as $site) {
|
foreach ($sites as $site) {
|
||||||
try {
|
try {
|
||||||
$ctrl = new UniFiController($site['unifi_controller_url'], $site['unifi_username'], Crypto::decrypt($site['unifi_password']), $site['site_id']);
|
$ctrl = new UniFiController($site['unifi_controller_url'], $site['unifi_username'], Crypto::decrypt($site['unifi_password']), $site['site_id'], $site['ssl_verify'] ?? 0);
|
||||||
$ctrl->syncVouchersToDatabase($db, $site['id']);
|
$ctrl->syncVouchersToDatabase($db, $site['id']);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$syncErrors[$site['id']] = $e->getMessage();
|
$syncErrors[$site['id']] = $e->getMessage();
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['save_settings'])) {
|
||||||
$settings['smtp_password'] = trim($_POST['smtp_password']);
|
$settings['smtp_password'] = trim($_POST['smtp_password']);
|
||||||
}
|
}
|
||||||
$settings['smtp_encryption'] = trim($_POST['smtp_encryption'] ?? 'tls');
|
$settings['smtp_encryption'] = trim($_POST['smtp_encryption'] ?? 'tls');
|
||||||
|
$settings['smtp_verify_ssl'] = isset($_POST['smtp_verify_ssl']) ? '1' : '0';
|
||||||
$settings['smtp_from_email'] = trim($_POST['smtp_from_email'] ?? '');
|
$settings['smtp_from_email'] = trim($_POST['smtp_from_email'] ?? '');
|
||||||
$settings['smtp_from_name'] = trim($_POST['smtp_from_name'] ?? '');
|
$settings['smtp_from_name'] = trim($_POST['smtp_from_name'] ?? '');
|
||||||
}
|
}
|
||||||
|
|
@ -204,6 +205,7 @@ $cs = [
|
||||||
'smtp_username' => $db->getSetting('smtp_username', ''),
|
'smtp_username' => $db->getSetting('smtp_username', ''),
|
||||||
'smtp_password' => $db->getSetting('smtp_password', ''),
|
'smtp_password' => $db->getSetting('smtp_password', ''),
|
||||||
'smtp_encryption' => $db->getSetting('smtp_encryption', 'tls'),
|
'smtp_encryption' => $db->getSetting('smtp_encryption', 'tls'),
|
||||||
|
'smtp_verify_ssl' => $db->getSetting('smtp_verify_ssl', '0'),
|
||||||
'smtp_from_email' => $db->getSetting('smtp_from_email', ''),
|
'smtp_from_email' => $db->getSetting('smtp_from_email', ''),
|
||||||
'smtp_from_name' => $db->getSetting('smtp_from_name', ''),
|
'smtp_from_name' => $db->getSetting('smtp_from_name', ''),
|
||||||
'system_url' => $db->getSetting('system_url', $autoDetectedUrl),
|
'system_url' => $db->getSetting('system_url', $autoDetectedUrl),
|
||||||
|
|
@ -427,6 +429,7 @@ $adminBase = '';
|
||||||
<div class="form-group"><label>Port</label><input type="number" name="smtp_port" value="<?= htmlspecialchars($cs['smtp_port']) ?>"></div>
|
<div class="form-group"><label>Port</label><input type="number" name="smtp_port" value="<?= htmlspecialchars($cs['smtp_port']) ?>"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group"><label>Verschlüsselung</label><select name="smtp_encryption"><option value="tls" <?= $cs['smtp_encryption']==='tls'?'selected':'' ?>>TLS</option><option value="ssl" <?= $cs['smtp_encryption']==='ssl'?'selected':'' ?>>SSL</option><option value="none" <?= $cs['smtp_encryption']==='none'?'selected':'' ?>>Keine</option></select></div>
|
<div class="form-group"><label>Verschlüsselung</label><select name="smtp_encryption"><option value="tls" <?= $cs['smtp_encryption']==='tls'?'selected':'' ?>>TLS</option><option value="ssl" <?= $cs['smtp_encryption']==='ssl'?'selected':'' ?>>SSL</option><option value="none" <?= $cs['smtp_encryption']==='none'?'selected':'' ?>>Keine</option></select></div>
|
||||||
|
<div class="checkbox-group" style="margin-bottom: 20px;"><input type="checkbox" name="smtp_verify_ssl" id="smtp_verify_ssl" <?= $cs['smtp_verify_ssl'] == '1' ? 'checked' : '' ?>><label for="smtp_verify_ssl" style="margin:0;"><?= __('smtp_verify_ssl') ?></label></div>
|
||||||
<div class="form-grid">
|
<div class="form-grid">
|
||||||
<div class="form-group"><label>Benutzername</label><input type="text" name="smtp_username" value="<?= htmlspecialchars($cs['smtp_username']) ?>"></div>
|
<div class="form-group"><label>Benutzername</label><input type="text" name="smtp_username" value="<?= htmlspecialchars($cs['smtp_username']) ?>"></div>
|
||||||
<div class="form-group"><label>Passwort</label><input type="password" name="smtp_password" placeholder="Leer = nicht ändern"></div>
|
<div class="form-group"><label>Passwort</label><input type="password" name="smtp_password" placeholder="Leer = nicht ändern"></div>
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,8 @@ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['ajax_test_site'])) {
|
||||||
$site['unifi_controller_url'],
|
$site['unifi_controller_url'],
|
||||||
$site['unifi_username'],
|
$site['unifi_username'],
|
||||||
Crypto::decrypt($site['unifi_password']),
|
Crypto::decrypt($site['unifi_password']),
|
||||||
$site['site_id']
|
$site['site_id'],
|
||||||
|
$site['ssl_verify'] ?? 0
|
||||||
);
|
);
|
||||||
echo json_encode([
|
echo json_encode([
|
||||||
'success' => $test === true,
|
'success' => $test === true,
|
||||||
|
|
@ -57,21 +58,22 @@ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['edit_site'])) {
|
||||||
$username = trim($_POST['username']);
|
$username = trim($_POST['username']);
|
||||||
$password = $_POST['password'];
|
$password = $_POST['password'];
|
||||||
$publicAccess = isset($_POST['public_access']) ? 1 : 0;
|
$publicAccess = isset($_POST['public_access']) ? 1 : 0;
|
||||||
|
$sslVerify = isset($_POST['ssl_verify']) ? 1 : 0;
|
||||||
if (empty($name)||empty($siteIdStr)||empty($controllerUrl)||empty($username)) throw new Exception(__('error_fill_all'));
|
if (empty($name)||empty($siteIdStr)||empty($controllerUrl)||empty($username)) throw new Exception(__('error_fill_all'));
|
||||||
if (!empty($password)) {
|
if (!empty($password)) {
|
||||||
$test = UniFiController::testConnection($controllerUrl,$username,$password,$siteIdStr);
|
$test = UniFiController::testConnection($controllerUrl,$username,$password,$siteIdStr,$sslVerify);
|
||||||
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
||||||
$db->execute("UPDATE sites SET name=?,site_id=?,unifi_controller_url=?,unifi_username=?,unifi_password=?,public_access=? WHERE id=?",
|
$db->execute("UPDATE sites SET name=?,site_id=?,unifi_controller_url=?,unifi_username=?,unifi_password=?,public_access=?,ssl_verify=? WHERE id=?",
|
||||||
[$name,$siteIdStr,$controllerUrl,$username,Crypto::encrypt($password),$publicAccess,$siteId]);
|
[$name,$siteIdStr,$controllerUrl,$username,Crypto::encrypt($password),$publicAccess,$sslVerify,$siteId]);
|
||||||
} else {
|
} else {
|
||||||
// Auch ohne Passwortaenderung testen (mit gespeichertem Passwort) –
|
// Auch ohne Passwortaenderung testen (mit gespeichertem Passwort) –
|
||||||
// sonst fallen Tippfehler in URL/Username erst beim naechsten Voucher auf.
|
// sonst fallen Tippfehler in URL/Username erst beim naechsten Voucher auf.
|
||||||
$stored = $db->fetchOne("SELECT unifi_password FROM sites WHERE id=?", [$siteId]);
|
$stored = $db->fetchOne("SELECT unifi_password FROM sites WHERE id=?", [$siteId]);
|
||||||
if (!$stored) throw new Exception(__('error_site_not_found'));
|
if (!$stored) throw new Exception(__('error_site_not_found'));
|
||||||
$test = UniFiController::testConnection($controllerUrl,$username,Crypto::decrypt($stored['unifi_password']),$siteIdStr);
|
$test = UniFiController::testConnection($controllerUrl,$username,Crypto::decrypt($stored['unifi_password']),$siteIdStr,$sslVerify);
|
||||||
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
||||||
$db->execute("UPDATE sites SET name=?,site_id=?,unifi_controller_url=?,unifi_username=?,public_access=? WHERE id=?",
|
$db->execute("UPDATE sites SET name=?,site_id=?,unifi_controller_url=?,unifi_username=?,public_access=?,ssl_verify=? WHERE id=?",
|
||||||
[$name,$siteIdStr,$controllerUrl,$username,$publicAccess,$siteId]);
|
[$name,$siteIdStr,$controllerUrl,$username,$publicAccess,$sslVerify,$siteId]);
|
||||||
}
|
}
|
||||||
$auth->writeAuditLog($_SESSION['user_id'],'site_edit','site',$siteId,"Site {$name} aktualisiert");
|
$auth->writeAuditLog($_SESSION['user_id'],'site_edit','site',$siteId,"Site {$name} aktualisiert");
|
||||||
flashSet(__('sites_updated'));
|
flashSet(__('sites_updated'));
|
||||||
|
|
@ -93,11 +95,12 @@ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['add_site'])) {
|
||||||
$username = trim($_POST['username']);
|
$username = trim($_POST['username']);
|
||||||
$password = $_POST['password'];
|
$password = $_POST['password'];
|
||||||
$publicAccess = isset($_POST['public_access']) ? 1 : 0;
|
$publicAccess = isset($_POST['public_access']) ? 1 : 0;
|
||||||
|
$sslVerify = isset($_POST['ssl_verify']) ? 1 : 0;
|
||||||
if (empty($name)||empty($siteId)||empty($controllerUrl)||empty($username)) throw new Exception(__('error_fill_all'));
|
if (empty($name)||empty($siteId)||empty($controllerUrl)||empty($username)) throw new Exception(__('error_fill_all'));
|
||||||
$test = UniFiController::testConnection($controllerUrl,$username,$password,$siteId);
|
$test = UniFiController::testConnection($controllerUrl,$username,$password,$siteId,$sslVerify);
|
||||||
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
if ($test !== true) throw new Exception(__('site_test_fail').': '.$test);
|
||||||
$newId = $db->execute("INSERT INTO sites (name,site_id,unifi_controller_url,unifi_username,unifi_password,public_access) VALUES (?,?,?,?,?,?)",
|
$newId = $db->execute("INSERT INTO sites (name,site_id,unifi_controller_url,unifi_username,unifi_password,public_access,ssl_verify) VALUES (?,?,?,?,?,?,?)",
|
||||||
[$name,$siteId,$controllerUrl,$username,Crypto::encrypt($password),$publicAccess]);
|
[$name,$siteId,$controllerUrl,$username,Crypto::encrypt($password),$publicAccess,$sslVerify]);
|
||||||
$auth->writeAuditLog($_SESSION['user_id'],'site_create','site',$newId,"Site {$name} erstellt");
|
$auth->writeAuditLog($_SESSION['user_id'],'site_create','site',$newId,"Site {$name} erstellt");
|
||||||
flashSet(__('sites_added'));
|
flashSet(__('sites_added'));
|
||||||
header('Location: sites.php');
|
header('Location: sites.php');
|
||||||
|
|
@ -237,7 +240,7 @@ $currentPage = 'sites';
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="site-actions">
|
<div class="site-actions">
|
||||||
<button onclick="openEditModal(<?= $site['id'] ?>, '<?= htmlspecialchars($site['name'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['site_id'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['unifi_controller_url'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['unifi_username'], ENT_QUOTES) ?>', <?= $site['public_access'] ?>)"
|
<button onclick="openEditModal(<?= $site['id'] ?>, '<?= htmlspecialchars($site['name'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['site_id'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['unifi_controller_url'], ENT_QUOTES) ?>', '<?= htmlspecialchars($site['unifi_username'], ENT_QUOTES) ?>', <?= $site['public_access'] ?>, <?= (int)($site['ssl_verify'] ?? 0) ?>)"
|
||||||
class="btn btn-secondary btn-sm">
|
class="btn btn-secondary btn-sm">
|
||||||
<i class="fas fa-edit"></i> <?= __('btn_edit') ?>
|
<i class="fas fa-edit"></i> <?= __('btn_edit') ?>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -309,6 +312,11 @@ $currentPage = 'sites';
|
||||||
<input type="checkbox" id="add_public" name="public_access">
|
<input type="checkbox" id="add_public" name="public_access">
|
||||||
<label for="add_public" style="margin:0;"><?= __('sites_public') ?></label>
|
<label for="add_public" style="margin:0;"><?= __('sites_public') ?></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group checkbox-group">
|
||||||
|
<input type="checkbox" id="add_ssl_verify" name="ssl_verify">
|
||||||
|
<label for="add_ssl_verify" style="margin:0;"><?= __('sites_ssl_verify') ?></label>
|
||||||
|
</div>
|
||||||
|
<small style="color:var(--text-muted);font-size:12px;display:block;margin-top:-10px;margin-bottom:14px;"><?= __('sites_ssl_verify_hint') ?></small>
|
||||||
<div style="display:flex;gap:10px;margin-top:20px;">
|
<div style="display:flex;gap:10px;margin-top:20px;">
|
||||||
<button type="submit" class="btn btn-primary" style="flex:1;" id="addSiteSubmitBtn">
|
<button type="submit" class="btn btn-primary" style="flex:1;" id="addSiteSubmitBtn">
|
||||||
<i class="fas fa-save"></i> <?= __('sites_add') ?>
|
<i class="fas fa-save"></i> <?= __('sites_add') ?>
|
||||||
|
|
@ -359,6 +367,11 @@ $currentPage = 'sites';
|
||||||
<input type="checkbox" id="edit_public_access" name="public_access">
|
<input type="checkbox" id="edit_public_access" name="public_access">
|
||||||
<label for="edit_public_access" style="margin:0;"><?= __('sites_public') ?></label>
|
<label for="edit_public_access" style="margin:0;"><?= __('sites_public') ?></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group checkbox-group">
|
||||||
|
<input type="checkbox" id="edit_ssl_verify" name="ssl_verify">
|
||||||
|
<label for="edit_ssl_verify" style="margin:0;"><?= __('sites_ssl_verify') ?></label>
|
||||||
|
</div>
|
||||||
|
<small style="color:var(--text-muted);font-size:12px;display:block;margin-top:-10px;margin-bottom:14px;"><?= __('sites_ssl_verify_hint') ?></small>
|
||||||
<div style="display:flex;gap:10px;margin-top:20px;">
|
<div style="display:flex;gap:10px;margin-top:20px;">
|
||||||
<button type="submit" class="btn btn-primary" style="flex:1;" id="editSiteSubmitBtn">
|
<button type="submit" class="btn btn-primary" style="flex:1;" id="editSiteSubmitBtn">
|
||||||
<i class="fas fa-save"></i> <?= __('btn_save') ?>
|
<i class="fas fa-save"></i> <?= __('btn_save') ?>
|
||||||
|
|
@ -376,7 +389,7 @@ $currentPage = 'sites';
|
||||||
function openModal() { document.getElementById('addSiteModal').classList.add('active'); }
|
function openModal() { document.getElementById('addSiteModal').classList.add('active'); }
|
||||||
function closeModal(id) { document.getElementById(id).classList.remove('active'); }
|
function closeModal(id) { document.getElementById(id).classList.remove('active'); }
|
||||||
|
|
||||||
function openEditModal(id, name, siteIdStr, controllerUrl, username, publicAccess) {
|
function openEditModal(id, name, siteIdStr, controllerUrl, username, publicAccess, sslVerify) {
|
||||||
document.getElementById('edit_site_id').value = id;
|
document.getElementById('edit_site_id').value = id;
|
||||||
document.getElementById('edit_name').value = name;
|
document.getElementById('edit_name').value = name;
|
||||||
document.getElementById('edit_site_id_str').value = siteIdStr;
|
document.getElementById('edit_site_id_str').value = siteIdStr;
|
||||||
|
|
@ -384,6 +397,7 @@ function openEditModal(id, name, siteIdStr, controllerUrl, username, publicAcces
|
||||||
document.getElementById('edit_username').value = username;
|
document.getElementById('edit_username').value = username;
|
||||||
document.getElementById('edit_password').value = '';
|
document.getElementById('edit_password').value = '';
|
||||||
document.getElementById('edit_public_access').checked = publicAccess == 1;
|
document.getElementById('edit_public_access').checked = publicAccess == 1;
|
||||||
|
document.getElementById('edit_ssl_verify').checked = sslVerify == 1;
|
||||||
document.getElementById('editSiteModal').classList.add('active');
|
document.getElementById('editSiteModal').classList.add('active');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ if (isset($_GET['ajax_get_vouchers']) && isset($_GET['site_id'])) {
|
||||||
if (!$site) { echo json_encode(['success'=>false,'message'=>__('error_site_not_found')]); exit; }
|
if (!$site) { echo json_encode(['success'=>false,'message'=>__('error_site_not_found')]); exit; }
|
||||||
if ($syncFirst) {
|
if ($syncFirst) {
|
||||||
try {
|
try {
|
||||||
$ctrl = new UniFiController($site['unifi_controller_url'],$site['unifi_username'],Crypto::decrypt($site['unifi_password']),$site['site_id']);
|
$ctrl = new UniFiController($site['unifi_controller_url'],$site['unifi_username'],Crypto::decrypt($site['unifi_password']),$site['site_id'],$site['ssl_verify'] ?? 0);
|
||||||
$ctrl->syncVouchersToDatabase($db,$siteId);
|
$ctrl->syncVouchersToDatabase($db,$siteId);
|
||||||
$db->execute("INSERT INTO settings (setting_key,setting_value) VALUES ('last_cron_sync',NOW()) ON DUPLICATE KEY UPDATE setting_value=NOW()");
|
$db->execute("INSERT INTO settings (setting_key,setting_value) VALUES ('last_cron_sync',NOW()) ON DUPLICATE KEY UPDATE setting_value=NOW()");
|
||||||
} catch (Exception $e) { error_log("Sync error: ".$e->getMessage()); }
|
} catch (Exception $e) { error_log("Sync error: ".$e->getMessage()); }
|
||||||
|
|
@ -89,7 +89,7 @@ if (isset($_POST['ajax_delete']) && isset($_POST['voucher_id']) && isset($_POST[
|
||||||
$siteId = (int)$_POST['site_id'];
|
$siteId = (int)$_POST['site_id'];
|
||||||
$site = $db->fetchOne("SELECT * FROM sites WHERE id=? AND is_active=1", [$siteId]);
|
$site = $db->fetchOne("SELECT * FROM sites WHERE id=? AND is_active=1", [$siteId]);
|
||||||
if (!$site) { echo json_encode(['success'=>false,'message'=>__('error_site_not_found')]); exit; }
|
if (!$site) { echo json_encode(['success'=>false,'message'=>__('error_site_not_found')]); exit; }
|
||||||
$ctrl = new UniFiController($site['unifi_controller_url'],$site['unifi_username'],Crypto::decrypt($site['unifi_password']),$site['site_id']);
|
$ctrl = new UniFiController($site['unifi_controller_url'],$site['unifi_username'],Crypto::decrypt($site['unifi_password']),$site['site_id'],$site['ssl_verify'] ?? 0);
|
||||||
if ($ctrl->deleteVoucher($voucherId)) {
|
if ($ctrl->deleteVoucher($voucherId)) {
|
||||||
$db->execute("DELETE FROM vouchers WHERE unifi_voucher_id=? AND site_id=?", [$voucherId,$siteId]);
|
$db->execute("DELETE FROM vouchers WHERE unifi_voucher_id=? AND site_id=?", [$voucherId,$siteId]);
|
||||||
echo json_encode(['success'=>true,'message'=>__('voucher_deleted')]);
|
echo json_encode(['success'=>true,'message'=>__('voucher_deleted')]);
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,8 @@ try {
|
||||||
$site['unifi_controller_url'],
|
$site['unifi_controller_url'],
|
||||||
$site['unifi_username'],
|
$site['unifi_username'],
|
||||||
Crypto::decrypt($site['unifi_password']),
|
Crypto::decrypt($site['unifi_password']),
|
||||||
$site['site_id']
|
$site['site_id'],
|
||||||
|
$site['ssl_verify'] ?? 0
|
||||||
);
|
);
|
||||||
|
|
||||||
$stats = $controller->syncVouchersToDatabase($db, $site['id']);
|
$stats = $controller->syncVouchersToDatabase($db, $site['id']);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ CREATE TABLE IF NOT EXISTS `sites` (
|
||||||
`unifi_password` VARCHAR(255) NOT NULL,
|
`unifi_password` VARCHAR(255) NOT NULL,
|
||||||
`is_active` TINYINT(1) DEFAULT 1,
|
`is_active` TINYINT(1) DEFAULT 1,
|
||||||
`public_access` TINYINT(1) DEFAULT 0,
|
`public_access` TINYINT(1) DEFAULT 0,
|
||||||
|
`ssl_verify` TINYINT(1) NOT NULL DEFAULT 0,
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
INDEX `idx_active` (`is_active`)
|
INDEX `idx_active` (`is_active`)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ class Mailer {
|
||||||
private $smtpUsername;
|
private $smtpUsername;
|
||||||
private $smtpPassword;
|
private $smtpPassword;
|
||||||
private $smtpEncryption;
|
private $smtpEncryption;
|
||||||
|
private $smtpVerifySsl;
|
||||||
private $fromEmail;
|
private $fromEmail;
|
||||||
private $fromName;
|
private $fromName;
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ class Mailer {
|
||||||
$this->smtpUsername = $this->db->getSetting('smtp_username', '');
|
$this->smtpUsername = $this->db->getSetting('smtp_username', '');
|
||||||
$this->smtpPassword = $this->db->getSetting('smtp_password', '');
|
$this->smtpPassword = $this->db->getSetting('smtp_password', '');
|
||||||
$this->smtpEncryption = $this->db->getSetting('smtp_encryption', 'tls');
|
$this->smtpEncryption = $this->db->getSetting('smtp_encryption', 'tls');
|
||||||
|
$this->smtpVerifySsl = $this->db->getSetting('smtp_verify_ssl', '0') === '1';
|
||||||
$this->fromEmail = $this->db->getSetting('smtp_from_email', 'noreply@' . ($_SERVER['HTTP_HOST'] ?? 'localhost'));
|
$this->fromEmail = $this->db->getSetting('smtp_from_email', 'noreply@' . ($_SERVER['HTTP_HOST'] ?? 'localhost'));
|
||||||
$this->fromName = $this->db->getSetting('smtp_from_name', $this->db->getSetting('app_title', 'UniFi Voucher System'));
|
$this->fromName = $this->db->getSetting('smtp_from_name', $this->db->getSetting('app_title', 'UniFi Voucher System'));
|
||||||
}
|
}
|
||||||
|
|
@ -122,11 +124,12 @@ class Mailer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function connectToSmtp() {
|
private function connectToSmtp() {
|
||||||
|
// Zertifikatspruefung optional aktivierbar (Setting smtp_verify_ssl)
|
||||||
$context = stream_context_create([
|
$context = stream_context_create([
|
||||||
'ssl' => [
|
'ssl' => [
|
||||||
'verify_peer' => false,
|
'verify_peer' => $this->smtpVerifySsl,
|
||||||
'verify_peer_name' => false,
|
'verify_peer_name' => $this->smtpVerifySsl,
|
||||||
'allow_self_signed' => true
|
'allow_self_signed' => !$this->smtpVerifySsl
|
||||||
]
|
]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,15 @@ class UniFiController {
|
||||||
private $csrfToken = null;
|
private $csrfToken = null;
|
||||||
private $sessionCookie = null;
|
private $sessionCookie = null;
|
||||||
private $loggedIn = false;
|
private $loggedIn = false;
|
||||||
|
/** SSL-Zertifikat pruefen? Default aus, da UnifFi-Controller meist self-signed sind. */
|
||||||
|
private $sslVerify = false;
|
||||||
|
|
||||||
public function __construct($controllerUrl, $username, $password, $siteId) {
|
public function __construct($controllerUrl, $username, $password, $siteId, $sslVerify = false) {
|
||||||
$this->controllerUrl = rtrim($controllerUrl, '/');
|
$this->controllerUrl = rtrim($controllerUrl, '/');
|
||||||
$this->username = $username;
|
$this->username = $username;
|
||||||
$this->password = $password;
|
$this->password = $password;
|
||||||
$this->siteId = $siteId;
|
$this->siteId = $siteId;
|
||||||
|
$this->sslVerify = (bool)$sslVerify;
|
||||||
$this->cookieFile = tempnam(sys_get_temp_dir(), 'UNIFI_');
|
$this->cookieFile = tempnam(sys_get_temp_dir(), 'UNIFI_');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,7 +44,8 @@ class UniFiController {
|
||||||
'password' => $this->password
|
'password' => $this->password
|
||||||
]),
|
]),
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_SSL_VERIFYPEER => false,
|
CURLOPT_SSL_VERIFYPEER => $this->sslVerify,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => $this->sslVerify ? 2 : 0,
|
||||||
CURLOPT_COOKIEJAR => $this->cookieFile,
|
CURLOPT_COOKIEJAR => $this->cookieFile,
|
||||||
CURLOPT_COOKIEFILE => $this->cookieFile,
|
CURLOPT_COOKIEFILE => $this->cookieFile,
|
||||||
CURLOPT_TIMEOUT => 10,
|
CURLOPT_TIMEOUT => 10,
|
||||||
|
|
@ -116,7 +120,8 @@ class UniFiController {
|
||||||
$options = [
|
$options = [
|
||||||
CURLOPT_URL => $url,
|
CURLOPT_URL => $url,
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
CURLOPT_SSL_VERIFYPEER => false,
|
CURLOPT_SSL_VERIFYPEER => $this->sslVerify,
|
||||||
|
CURLOPT_SSL_VERIFYHOST => $this->sslVerify ? 2 : 0,
|
||||||
CURLOPT_TIMEOUT => 10,
|
CURLOPT_TIMEOUT => 10,
|
||||||
CURLOPT_CONNECTTIMEOUT => 5,
|
CURLOPT_CONNECTTIMEOUT => 5,
|
||||||
CURLOPT_HTTPHEADER => $headers
|
CURLOPT_HTTPHEADER => $headers
|
||||||
|
|
@ -325,9 +330,9 @@ class UniFiController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verbindung testen
|
// Verbindung testen
|
||||||
public static function testConnection($controllerUrl, $username, $password, $siteId) {
|
public static function testConnection($controllerUrl, $username, $password, $siteId, $sslVerify = false) {
|
||||||
try {
|
try {
|
||||||
$controller = new self($controllerUrl, $username, $password, $siteId);
|
$controller = new self($controllerUrl, $username, $password, $siteId, $sslVerify);
|
||||||
$controller->login();
|
$controller->login();
|
||||||
return true;
|
return true;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,8 @@ function doCreateVoucher($db, $site, $voucherName, $maxUses, $expireMinutes, $us
|
||||||
$site['unifi_controller_url'],
|
$site['unifi_controller_url'],
|
||||||
$site['unifi_username'],
|
$site['unifi_username'],
|
||||||
Crypto::decrypt($site['unifi_password']),
|
Crypto::decrypt($site['unifi_password']),
|
||||||
$site['site_id']
|
$site['site_id'],
|
||||||
|
$site['ssl_verify'] ?? 0
|
||||||
);
|
);
|
||||||
$voucher = $controller->createVoucher($fullName, $maxUses, $expireMinutes);
|
$voucher = $controller->createVoucher($fullName, $maxUses, $expireMinutes);
|
||||||
if (!is_array($voucher) || empty($voucher['formatted_code'])) {
|
if (!is_array($voucher) || empty($voucher['formatted_code'])) {
|
||||||
|
|
@ -251,7 +252,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['create_bulk'])) {
|
||||||
$site['unifi_controller_url'],
|
$site['unifi_controller_url'],
|
||||||
$site['unifi_username'],
|
$site['unifi_username'],
|
||||||
Crypto::decrypt($site['unifi_password']),
|
Crypto::decrypt($site['unifi_password']),
|
||||||
$site['site_id']
|
$site['site_id'],
|
||||||
|
$site['ssl_verify'] ?? 0
|
||||||
);
|
);
|
||||||
$created = $controller->createVouchers($fullName, $maxUses, $expireMinutes, $bulkCount);
|
$created = $controller->createVouchers($fullName, $maxUses, $expireMinutes, $bulkCount);
|
||||||
$expiryTs = time() + ($expireMinutes * 60);
|
$expiryTs = time() + ($expireMinutes * 60);
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,11 @@ return [
|
||||||
'cron_token_deleted' => 'Cron-Token wurde gelöscht!',
|
'cron_token_deleted' => 'Cron-Token wurde gelöscht!',
|
||||||
'm365_secret_hint' => 'Leer lassen = nicht ändern. Zum Deaktivieren des M365-Logins die Client ID leeren.',
|
'm365_secret_hint' => 'Leer lassen = nicht ändern. Zum Deaktivieren des M365-Logins die Client ID leeren.',
|
||||||
|
|
||||||
|
// SSL-Verifizierung
|
||||||
|
'sites_ssl_verify' => 'SSL-Zertifikat des Controllers prüfen',
|
||||||
|
'sites_ssl_verify_hint' => 'Nur aktivieren, wenn der Controller ein gültiges Zertifikat besitzt (UniFi nutzt standardmäßig self-signed).',
|
||||||
|
'smtp_verify_ssl' => 'SSL-Zertifikat des SMTP-Servers prüfen',
|
||||||
|
|
||||||
// Site connection test
|
// Site connection test
|
||||||
'site_test_btn' => 'Verbindung testen',
|
'site_test_btn' => 'Verbindung testen',
|
||||||
'site_test_ok' => 'Verbindung erfolgreich',
|
'site_test_ok' => 'Verbindung erfolgreich',
|
||||||
|
|
|
||||||
|
|
@ -334,6 +334,11 @@ return [
|
||||||
'cron_token_deleted' => 'Cron token deleted!',
|
'cron_token_deleted' => 'Cron token deleted!',
|
||||||
'm365_secret_hint' => 'Leave empty to keep the current secret. To disable M365 login, clear the Client ID.',
|
'm365_secret_hint' => 'Leave empty to keep the current secret. To disable M365 login, clear the Client ID.',
|
||||||
|
|
||||||
|
// SSL verification
|
||||||
|
'sites_ssl_verify' => "Verify the controller's SSL certificate",
|
||||||
|
'sites_ssl_verify_hint' => 'Only enable if the controller has a valid certificate (UniFi uses self-signed certificates by default).',
|
||||||
|
'smtp_verify_ssl' => "Verify the SMTP server's SSL certificate",
|
||||||
|
|
||||||
// Site connection test
|
// Site connection test
|
||||||
'site_test_btn' => 'Test connection',
|
'site_test_btn' => 'Test connection',
|
||||||
'site_test_ok' => 'Connection successful',
|
'site_test_ok' => 'Connection successful',
|
||||||
|
|
|
||||||
3
updater/migrations/0003_sites_ssl_verify.sql
Normal file
3
updater/migrations/0003_sites_ssl_verify.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
-- Opt-in SSL-Zertifikatspruefung pro Site (Default aus: UniFi-Controller
|
||||||
|
-- nutzen meist self-signed Zertifikate).
|
||||||
|
ALTER TABLE `sites` ADD COLUMN `ssl_verify` TINYINT(1) NOT NULL DEFAULT 0;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue