Added SMTP Provider and the ability to share OAUTH keys with IMAP for M365 Mail Auth

This commit is contained in:
johnnyq 2025-09-15 17:23:00 -04:00
parent 902323a75b
commit dc0715da57
7 changed files with 220 additions and 188 deletions

View File

@ -3983,11 +3983,20 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.3'"); mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.3'");
} }
if (CURRENT_DATABASE_VERSION == '2.3.3') {
mysqli_query($mysqli, "ALTER TABLE settings
ADD `config_smtp_provider` ENUM('standard_smtp','google_oauth','microsoft_oauth') NULL DEFAULT NULL AFTER `config_start_page`
");
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.4'");
}
// if (CURRENT_DATABASE_VERSION == '2.3.3') { // if (CURRENT_DATABASE_VERSION == '2.3.4') {
// // Insert queries here required to update to DB version 2.3.3 // // Insert queries here required to update to DB version 2.3.4
// // Then, update the database to the next sequential version // // Then, update the database to the next sequential version
// mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.4'"); // mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.5'");
// } // }
} else { } else {

View File

@ -3,114 +3,87 @@
defined('FROM_POST_HANDLER') || die("Direct file access is not allowed"); defined('FROM_POST_HANDLER') || die("Direct file access is not allowed");
if (isset($_POST['edit_mail_smtp_settings'])) { if (isset($_POST['edit_mail_smtp_settings'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
$config_smtp_host = sanitizeInput($_POST['config_smtp_host']); $config_smtp_provider = sanitizeInput($_POST['config_smtp_provider'] ?? 'standard_smtp');
$config_smtp_port = intval($_POST['config_smtp_port']); $config_smtp_host = sanitizeInput($_POST['config_smtp_host']);
$config_smtp_encryption = sanitizeInput($_POST['config_smtp_encryption']); $config_smtp_port = intval($_POST['config_smtp_port'] ?? 0);
$config_smtp_username = sanitizeInput($_POST['config_smtp_username']); $config_smtp_encryption = sanitizeInput($_POST['config_smtp_encryption']);
$config_smtp_password = sanitizeInput($_POST['config_smtp_password']); $config_smtp_username = sanitizeInput($_POST['config_smtp_username']);
$config_smtp_password = sanitizeInput($_POST['config_smtp_password']);
mysqli_query($mysqli,"UPDATE settings SET config_smtp_host = '$config_smtp_host', config_smtp_port = $config_smtp_port, config_smtp_encryption = '$config_smtp_encryption', config_smtp_username = '$config_smtp_username', config_smtp_password = '$config_smtp_password' WHERE company_id = 1"); // Shared OAuth fields
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
logAction("Settings", "Edit", "$session_name edited SMTP mail settings"); mysqli_query($mysqli, "
UPDATE settings SET
config_smtp_provider = " . ($config_smtp_provider === 'none' ? "NULL" : "'$config_smtp_provider'") . ",
config_smtp_host = '$config_smtp_host',
config_smtp_port = $config_smtp_port,
config_smtp_encryption = '$config_smtp_encryption',
config_smtp_username = '$config_smtp_username',
config_smtp_password = '$config_smtp_password',
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
config_mail_oauth_access_token = '$config_mail_oauth_access_token'
WHERE company_id = 1
");
logAction("Settings", "Edit", "$session_name edited SMTP settings");
flash_alert("SMTP Mail Settings updated"); flash_alert("SMTP Mail Settings updated");
redirect(); redirect();
} }
if (isset($_POST['edit_mail_imap_settings'])) { if (isset($_POST['edit_mail_imap_settings'])) {
validateCSRFToken($_POST['csrf_token']); validateCSRFToken($_POST['csrf_token']);
// Provider ('' -> NULL allowed) $config_imap_provider = sanitizeInput($_POST['config_imap_provider'] ?? 'standard_imap');
$config_imap_provider = sanitizeInput($_POST['config_imap_provider']); $config_imap_host = sanitizeInput($_POST['config_imap_host']);
$allowed_providers = ['standard_imap','google_oauth','microsoft_oauth']; $config_imap_port = intval($_POST['config_imap_port'] ?? 0);
if ($config_imap_provider !== '' && !in_array($config_imap_provider, $allowed_providers, true)) { $config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']);
$config_imap_provider = 'standard_imap'; // fallback $config_imap_username = sanitizeInput($_POST['config_imap_username']);
} $config_imap_password = sanitizeInput($_POST['config_imap_password']);
// Standard IMAP fields (kept for all providers; OAuth still needs these endpoints) // Shared OAuth fields
$config_imap_host = sanitizeInput($_POST['config_imap_host']); $config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
$config_imap_port = (int) sanitizeInput($_POST['config_imap_port']); $config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
$config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']); // '', 'tls', 'ssl' $config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']);
$config_imap_username = sanitizeInput($_POST['config_imap_username']); $config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
$config_imap_password = sanitizeInput($_POST['config_imap_password']); // ignored if OAuth selected $config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']);
// Shared OAuth fields (may or may not be present in your form yet) mysqli_query($mysqli, "
$config_mail_oauth_client_id = sanitizeInput($_POST['config_mail_oauth_client_id']);
$config_mail_oauth_client_secret = sanitizeInput($_POST['config_mail_oauth_client_secret']);
$config_mail_oauth_tenant_id = sanitizeInput($_POST['config_mail_oauth_tenant_id']); // M365 only; harmless to keep when Google
$config_mail_oauth_refresh_token = sanitizeInput($_POST['config_mail_oauth_refresh_token']);
$config_mail_oauth_access_token = sanitizeInput($_POST['config_mail_oauth_access_token']); // optional manual paste
$config_mail_oauth_access_token_expires_at = sanitizeInput($_POST['config_mail_oauth_access_token_expires_at']); // 'YYYY-mm-dd HH:ii:ss' optional
// If provider is not OAuth, purge OAuth values on save
$is_oauth = ($config_imap_provider === 'google_oauth' || $config_imap_provider === 'microsoft_oauth');
// Detect refresh token change to invalidate access token cache
// (Relies on $config_mail_oauth_refresh_token loaded earlier with settings)
$refresh_changed = false;
if ($is_oauth) {
$prev_refresh = isset($config_mail_oauth_refresh_token_current) ? $config_mail_oauth_refresh_token_current : ($config_mail_oauth_refresh_token ?? '');
// If you already load settings into $config_mail_oauth_refresh_token, use that:
if (isset($config_mail_oauth_refresh_token)) {
$prev_refresh = $config_mail_oauth_refresh_token;
}
$refresh_changed = ($config_mail_oauth_refresh_token !== '' && $config_mail_oauth_refresh_token !== $prev_refresh)
|| ($config_mail_oauth_refresh_token === '' && $prev_refresh !== '');
}
// If OAuth refresh changed or provider just switched to non-OAuth, clear access token values
if (!$is_oauth || $refresh_changed) {
$config_mail_oauth_access_token = '';
$config_mail_oauth_access_token_expires_at = '';
}
// Helper for NULL / quoted values
$q = fn($v) => ($v !== '' ? "'" . mysqli_real_escape_string($mysqli, $v) . "'" : "NULL");
// Build UPDATE with correct NULL handling
$sql = "
UPDATE settings SET UPDATE settings SET
config_imap_provider = " . ($config_imap_provider !== '' ? $q($config_imap_provider) : "NULL") . ", config_imap_provider = " . ($config_imap_provider === 'none' ? "NULL" : "'$config_imap_provider'") . ",
config_imap_host = " . $q($config_imap_host) . ", config_imap_host = '$config_imap_host',
config_imap_port = " . (int)$config_imap_port . ", config_imap_port = $config_imap_port,
config_imap_encryption = " . $q($config_imap_encryption) . ", config_imap_encryption = '$config_imap_encryption',
config_imap_username = " . $q($config_imap_username) . ", config_imap_username = '$config_imap_username',
config_imap_password = " . ($is_oauth ? "NULL" : $q($config_imap_password)) . ", config_imap_password = '$config_imap_password',
config_mail_oauth_client_id = '$config_mail_oauth_client_id',
-- Shared OAuth fields (kept even if provider is Google or Microsoft; NULL if not used) config_mail_oauth_client_secret = '$config_mail_oauth_client_secret',
config_mail_oauth_client_id = " . ($is_oauth ? $q($config_mail_oauth_client_id) : "NULL") . ", config_mail_oauth_tenant_id = '$config_mail_oauth_tenant_id',
config_mail_oauth_client_secret = " . ($is_oauth ? $q($config_mail_oauth_client_secret) : "NULL") . ", config_mail_oauth_refresh_token = '$config_mail_oauth_refresh_token',
config_mail_oauth_tenant_id = " . ($is_oauth ? $q($config_mail_oauth_tenant_id) : "NULL") . ", config_mail_oauth_access_token = '$config_mail_oauth_access_token'
config_mail_oauth_refresh_token = " . ($is_oauth ? $q($config_mail_oauth_refresh_token) : "NULL") . ",
config_mail_oauth_access_token = " . ($is_oauth ? $q($config_mail_oauth_access_token) : "NULL") . ",
config_mail_oauth_access_token_expires_at = " . ($is_oauth ? $q($config_mail_oauth_access_token_expires_at) : "NULL") . "
WHERE company_id = 1 WHERE company_id = 1
"; ");
mysqli_query($mysqli, $sql);
logAction("Settings", "Edit", "$session_name edited IMAP/OAuth mail settings");
// Friendly hint about what was saved
if ($config_imap_provider === '') {
flash_alert("IMAP monitoring disabled (provider not configured).");
} elseif ($config_imap_provider === 'standard_imap') {
flash_alert("IMAP settings updated (standard username/password).");
} elseif ($config_imap_provider === 'google_oauth') {
flash_alert("IMAP settings updated for Google Workspace (OAuth).");
} elseif ($config_imap_provider === 'microsoft_oauth') {
flash_alert("IMAP settings updated for Microsoft 365 (OAuth).");
} else {
flash_alert("IMAP settings updated.");
}
logAction("Settings", "Edit", "$session_name edited IMAP settings");
flash_alert("IMAP Mail Settings updated");
redirect(); redirect();
} }
if (isset($_POST['edit_mail_from_settings'])) { if (isset($_POST['edit_mail_from_settings'])) {

View File

@ -10,61 +10,87 @@ require_once "includes/inc_all_admin.php";
<form action="post.php" method="post" autocomplete="off"> <form action="post.php" method="post" autocomplete="off">
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>"> <input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
<!-- SMTP Provider -->
<div class="form-group"> <div class="form-group">
<label>SMTP Host</label> <label>SMTP Provider</label>
<div class="input-group"> <div class="input-group">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-server"></i></span> <span class="input-group-text"><i class="fa fa-fw fa-cloud"></i></span>
</div> </div>
<input type="text" class="form-control" name="config_smtp_host" placeholder="Mail Server Address" value="<?php echo nullable_htmlentities($config_smtp_host); ?>" required> <select class="form-control" name="config_smtp_provider" id="config_smtp_provider">
</div> <option value="none" <?php if(($config_smtp_provider ?? '')==='none' || ($config_smtp_provider ?? '')==='') echo 'selected'; ?>>None (Disabled)</option>
</div> <option value="standard_smtp" <?php if(($config_smtp_provider ?? 'standard_smtp')==='standard_smtp') echo 'selected'; ?>>Standard SMTP (Username/Password)</option>
<option value="google_oauth" <?php if(($config_smtp_provider ?? '')==='google_oauth') echo 'selected'; ?>>Google Workspace (OAuth)</option>
<div class="form-group"> <option value="microsoft_oauth" <?php if(($config_smtp_provider ?? '')==='microsoft_oauth') echo 'selected'; ?>>Microsoft 365 (OAuth)</option>
<label>SMTP Port</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-plug"></i></span>
</div>
<input type="number" min="0" class="form-control" name="config_smtp_port" placeholder="Mail Server Port Number" value="<?php echo intval($config_smtp_port); ?>" required>
</div>
</div>
<div class="form-group">
<label>Encryption</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<select class="form-control" name="config_smtp_encryption">
<option value=''>None</option>
<option <?php if ($config_smtp_encryption == 'tls') { echo "selected"; } ?> value="tls">TLS</option>
<option <?php if ($config_smtp_encryption == 'ssl') { echo "selected"; } ?> value="ssl">SSL</option>
</select> </select>
</div> </div>
<small class="text-secondary d-block mt-1" id="smtp_provider_hint">
Choose your SMTP provider. OAuth options ignore the SMTP password here.
</small>
</div> </div>
<div class="form-group">
<label>SMTP Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="config_smtp_username" placeholder="Username (Leave blank if no auth is required)" value="<?php echo nullable_htmlentities($config_smtp_username); ?>">
</div>
</div>
<div class="form-group"> <!-- Standard SMTP fields (show only for standard_smtp) -->
<label>SMTP Password</label> <div id="smtp_standard_fields">
<div class="input-group"> <div class="form-group">
<div class="input-group-prepend"> <label>SMTP Host</label>
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span> <div class="input-group">
</div> <div class="input-group-prepend">
<input type="password" class="form-control" data-toggle="password" name="config_smtp_password" placeholder="Password (Leave blank if no auth is required)" value="<?php echo nullable_htmlentities($config_smtp_password); ?>" autocomplete="new-password"> <span class="input-group-text"><i class="fa fa-fw fa-server"></i></span>
<div class="input-group-append"> </div>
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span> <input type="text" class="form-control" name="config_smtp_host" placeholder="Mail Server Address" value="<?php echo nullable_htmlentities($config_smtp_host); ?>" required>
</div> </div>
</div> </div>
<div class="form-group">
<label>SMTP Port</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-plug"></i></span>
</div>
<input type="number" min="0" class="form-control" name="config_smtp_port" placeholder="Mail Server Port Number" value="<?php echo intval($config_smtp_port); ?>" required>
</div>
</div>
<div class="form-group">
<label>Encryption</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-lock"></i></span>
</div>
<select class="form-control" name="config_smtp_encryption">
<option value=''>None</option>
<option <?php if ($config_smtp_encryption == 'tls') { echo "selected"; } ?> value="tls">TLS</option>
<option <?php if ($config_smtp_encryption == 'ssl') { echo "selected"; } ?> value="ssl">SSL</option>
</select>
</div>
</div>
<div class="form-group">
<label>SMTP Username</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
</div>
<input type="text" class="form-control" name="config_smtp_username" placeholder="Username (Leave blank if no auth is required)" value="<?php echo nullable_htmlentities($config_smtp_username); ?>">
</div>
</div>
<div class="form-group" id="smtp_password_group">
<div class="form-group">
<label>SMTP Password</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-key"></i></span>
</div>
<input type="password" class="form-control" data-toggle="password" name="config_smtp_password" placeholder="Password (Leave blank if no auth is required)" value="<?php echo nullable_htmlentities($config_smtp_password); ?>" autocomplete="new-password">
<div class="input-group-append">
<span class="input-group-text"><i class="fa fa-fw fa-eye"></i></span>
</div>
</div>
</div>
</div>
</div> </div>
<hr> <hr>
@ -159,9 +185,10 @@ require_once "includes/inc_all_admin.php";
</div> </div>
</div> </div>
<div id="oauth_fields" style="display:none;"> <!-- OAuth shared fields (show for google_oauth / microsoft_oauth) -->
<div id="smtp_oauth_fields" style="display:none;">
<hr> <hr>
<h5 class="mb-2">OAuth Settings</h5> <h5 class="mb-2">OAuth Settings (shared for IMAP & SMTP)</h5>
<p class="text-secondary" id="oauth_hint"> <p class="text-secondary" id="oauth_hint">
Configure OAuth credentials for the selected provider. Configure OAuth credentials for the selected provider.
</p> </p>
@ -403,64 +430,65 @@ require_once "includes/inc_all_admin.php";
<script> <script>
(function(){ (function(){
const sel = document.getElementById('config_imap_provider');
const pwdGrp = document.getElementById('imap_password_group');
const oauthWrap = document.getElementById('oauth_fields');
const standardWrap = document.getElementById('standard_fields');
const tenantRow = document.getElementById('tenant_row');
const oauthHint = document.getElementById('oauth_hint');
const providerHint = document.getElementById('imap_provider_hint');
function setDisabled(container, disabled){ function setDisabled(container, disabled){
if(!container) return; if(!container) return;
container.querySelectorAll('input, select, textarea').forEach(el => { container.querySelectorAll('input, select, textarea').forEach(el => el.disabled = !!disabled);
el.disabled = !!disabled;
});
} }
function toggleFields(){ function wireProvider(selectId, standardWrapId, passwordGroupId, oauthWrapId, tenantRowId, hintId, oauthHintId){
if(!sel) return; const sel = document.getElementById(selectId);
const v = sel.value || ''; const std = document.getElementById(standardWrapId);
const isNone = v === ''; const pwd = document.getElementById(passwordGroupId);
const isStd = v === 'standard_imap'; const oauth = document.getElementById(oauthWrapId);
const isG = v === 'google_oauth'; const ten = document.getElementById(tenantRowId);
const isM = v === 'microsoft_oauth'; const hint = document.getElementById(hintId);
const isOAuth = isG || isM; const ohint = document.getElementById(oauthHintId);
// Show/hide containers function toggle(){
if (pwdGrp) pwdGrp.style.display = isStd ? '' : 'none'; const v = (sel && sel.value) || '';
if (oauthWrap) oauthWrap.style.display = isOAuth ? '' : 'none'; const isNone = (v === 'none' || v === '');
if (standardWrap) standardWrap.style.display = isStd ? '' : 'none'; const isStd = v === 'standard_smtp' || v === 'standard_imap';
if (tenantRow) tenantRow.style.display = isM ? '' : 'none'; const isG = v === 'google_oauth';
const isM = v === 'microsoft_oauth';
const isOAuth = isG || isM;
// Disable inputs inside hidden sections to avoid accidental submission if (std) std.style.display = isStd ? '' : 'none';
setDisabled(pwdGrp, !isStd); if (pwd) pwd.style.display = isStd ? '' : 'none';
setDisabled(standardWrap, !isStd); if (oauth) oauth.style.display = isOAuth ? '' : 'none';
setDisabled(oauthWrap, !isOAuth); if (ten) ten.style.display = isM ? '' : 'none';
// Update hints setDisabled(std, !isStd);
if (providerHint) { setDisabled(pwd, !isStd);
providerHint.textContent = isNone setDisabled(oauth, !isOAuth);
? 'Choose a provider to reveal the relevant settings.'
: isStd if (hint) {
? 'Standard IMAP: provide host, port, encryption, username, and password.' hint.textContent = isNone
: isG ? 'Disabled.'
? 'Google Workspace OAuth: provide Client ID & Secret; paste the refresh token; username should be the mailbox address.' : isStd
: 'Microsoft 365 OAuth: provide Client ID, Secret & Tenant ID; paste the refresh token; username should be the mailbox address.'; ? 'Standard: provide host, port, encryption, username & password.'
} : isG
if (oauthHint) { ? 'Google OAuth: set Client ID/Secret; paste a refresh token; username should be the mailbox email.'
oauthHint.textContent = isG : 'Microsoft 365 OAuth: set Client ID/Secret/Tenant; paste a refresh token; username should be the mailbox email.';
? 'Google Workspace OAuth: Client ID & Secret from Google Cloud; Refresh token generated via OAuth consent.' }
: isM if (ohint) {
? 'Microsoft 365 OAuth: Client ID, Secret & Tenant ID from Entra ID; Refresh token generated via OAuth consent.' ohint.textContent = isG
: 'Configure OAuth credentials for the selected provider.'; ? 'Google Workspace OAuth: Client ID/Secret from Google Cloud; Refresh token via consent.'
: isM
? 'Microsoft 365 OAuth: Client ID/Secret/Tenant from Entra ID; Refresh token via consent.'
: 'Configure OAuth credentials for the selected provider.';
}
} }
if (sel) { sel.addEventListener('change', toggle); toggle(); }
} }
if (sel) { // IMAP (you already have these IDs in your page)
sel.addEventListener('change', toggleFields); wireProvider('config_imap_provider', 'standard_fields', 'imap_password_group',
toggleFields(); 'oauth_fields', 'tenant_row', 'imap_provider_hint', 'oauth_hint');
}
// SMTP (the IDs we just added)
wireProvider('config_smtp_provider', 'smtp_standard_fields', 'smtp_password_group',
'smtp_oauth_fields', 'smtp_tenant_row', 'smtp_provider_hint', 'smtp_oauth_hint');
})(); })();
</script> </script>

3
db.sql
View File

@ -1981,6 +1981,7 @@ CREATE TABLE `settings` (
`company_id` int(11) NOT NULL, `company_id` int(11) NOT NULL,
`config_current_database_version` varchar(10) NOT NULL, `config_current_database_version` varchar(10) NOT NULL,
`config_start_page` varchar(200) DEFAULT 'clients.php', `config_start_page` varchar(200) DEFAULT 'clients.php',
`config_smtp_provider` enum('standard_smtp','google_oauth','microsoft_oauth') DEFAULT NULL,
`config_smtp_host` varchar(200) DEFAULT NULL, `config_smtp_host` varchar(200) DEFAULT NULL,
`config_smtp_port` int(5) DEFAULT NULL, `config_smtp_port` int(5) DEFAULT NULL,
`config_smtp_encryption` varchar(200) DEFAULT NULL, `config_smtp_encryption` varchar(200) DEFAULT NULL,
@ -2765,4 +2766,4 @@ CREATE TABLE `vendors` (
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2025-09-12 15:55:31 -- Dump completed on 2025-09-15 17:22:23

View File

@ -7,10 +7,13 @@ DEFINE("WORDING_ROLECHECK_FAILED", "You are not permitted to do that!");
require_once "plugins/PHPMailer/src/Exception.php"; require_once "plugins/PHPMailer/src/Exception.php";
require_once "plugins/PHPMailer/src/PHPMailer.php"; require_once "plugins/PHPMailer/src/PHPMailer.php";
require_once "plugins/PHPMailer/src/SMTP.php"; require_once "plugins/PHPMailer/src/SMTP.php";
require_once "plugins/PHPMailer/src/OAuthTokenProvider.php";
require_once "plugins/PHPMailer/src/OAuth.php";
// Initiate PHPMailer // Initiate PHPMailer
use PHPMailer\PHPMailer\PHPMailer; use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception; use PHPMailer\PHPMailer\Exception;
use PHPMailer\PHPMailer\OAuthTokenProvider;
// Function to generate both crypto & URL safe random strings // Function to generate both crypto & URL safe random strings
function randomString($length = 16) { function randomString($length = 16) {
@ -688,6 +691,23 @@ function validateAccountantRole() {
} }
} }
/**
* Minimal token provider for PHPMailer XOAUTH2 without external deps.
*/
class StaticTokenProvider implements OAuthTokenProvider {
private $email;
private $accessToken;
public function __construct(string $email, string $accessToken) {
$this->email = $email;
$this->accessToken = $accessToken;
}
public function getOauth64(): string {
// XOAUTH2 SASL string: "user=<email>\x01auth=Bearer <token>\x01\x01"
$authString = "user={$this->email}\x01auth=Bearer {$this->accessToken}\x01\x01";
return base64_encode($authString);
}
}
// Send a single email to a single recipient // Send a single email to a single recipient
function sendSingleEmail($config_smtp_host, $config_smtp_username, $config_smtp_password, $config_smtp_encryption, $config_smtp_port, $from_email, $from_name, $to_email, $to_name, $subject, $body, $ics_str) function sendSingleEmail($config_smtp_host, $config_smtp_username, $config_smtp_password, $config_smtp_encryption, $config_smtp_port, $from_email, $from_name, $to_email, $to_name, $subject, $body, $ics_str)
{ {

View File

@ -5,4 +5,4 @@
* It is used in conjunction with database_updates.php * It is used in conjunction with database_updates.php
*/ */
DEFINE("LATEST_DATABASE_VERSION", "2.3.3"); DEFINE("LATEST_DATABASE_VERSION", "2.3.4");

View File

@ -12,6 +12,7 @@ $config_azure_client_id = $row['config_azure_client_id'];
$config_azure_client_secret = $row['config_azure_client_secret']; $config_azure_client_secret = $row['config_azure_client_secret'];
// Mail - SMTP // Mail - SMTP
$config_smtp_provider = $row['config_smtp_provider'];
$config_smtp_host = $row['config_smtp_host']; $config_smtp_host = $row['config_smtp_host'];
$config_smtp_port = intval($row['config_smtp_port']); $config_smtp_port = intval($row['config_smtp_port']);
$config_smtp_encryption = $row['config_smtp_encryption']; $config_smtp_encryption = $row['config_smtp_encryption'];