mirror of https://github.com/itflow-org/itflow
Added Beta support for Microsoft IMAP OAUTH2 must use new mail parser for it to work cron/ticket_email_parser.php
This commit is contained in:
parent
ce7d84aa2f
commit
3a5b18f3dd
|
|
@ -3968,11 +3968,26 @@ if (LATEST_DATABASE_VERSION > CURRENT_DATABASE_VERSION) {
|
|||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.2'");
|
||||
}
|
||||
|
||||
if (CURRENT_DATABASE_VERSION == '2.3.2') {
|
||||
|
||||
mysqli_query($mysqli, "ALTER TABLE settings
|
||||
ADD `config_imap_provider` ENUM('standard_imap','google_oauth','microsoft_oauth') NULL DEFAULT NULL AFTER `config_mail_from_name`,
|
||||
ADD `config_mail_oauth_client_id` VARCHAR(255) NULL AFTER `config_imap_provider`,
|
||||
ADD `config_mail_oauth_client_secret` VARCHAR(255) NULL AFTER `config_mail_oauth_client_id`,
|
||||
ADD `config_mail_oauth_tenant_id` VARCHAR(255) NULL AFTER `config_mail_oauth_client_secret`,
|
||||
ADD `config_mail_oauth_refresh_token` TEXT NULL AFTER `config_mail_oauth_tenant_id`,
|
||||
ADD `config_mail_oauth_access_token` TEXT NULL AFTER `config_mail_oauth_refresh_token`,
|
||||
ADD `config_mail_oauth_access_token_expires_at` DATETIME NULL AFTER `config_mail_oauth_access_token`
|
||||
");
|
||||
|
||||
mysqli_query($mysqli, "UPDATE `settings` SET `config_current_database_version` = '2.3.3'");
|
||||
}
|
||||
|
||||
// if (CURRENT_DATABASE_VERSION == '2.3.2') {
|
||||
// if (CURRENT_DATABASE_VERSION == '2.3.3') {
|
||||
// // Insert queries here required to update to DB version 2.3.3
|
||||
// // Then, update the database to the next sequential 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.4'");
|
||||
// }
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -26,20 +26,91 @@ if (isset($_POST['edit_mail_imap_settings'])) {
|
|||
|
||||
validateCSRFToken($_POST['csrf_token']);
|
||||
|
||||
$config_imap_host = sanitizeInput($_POST['config_imap_host']);
|
||||
$config_imap_username = sanitizeInput($_POST['config_imap_username']);
|
||||
$config_imap_password = sanitizeInput($_POST['config_imap_password']);
|
||||
$config_imap_port = intval($_POST['config_imap_port']);
|
||||
$config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']);
|
||||
// Provider ('' -> NULL allowed)
|
||||
$config_imap_provider = sanitizeInput($_POST['config_imap_provider']);
|
||||
$allowed_providers = ['standard_imap','google_oauth','microsoft_oauth'];
|
||||
if ($config_imap_provider !== '' && !in_array($config_imap_provider, $allowed_providers, true)) {
|
||||
$config_imap_provider = 'standard_imap'; // fallback
|
||||
}
|
||||
|
||||
mysqli_query($mysqli,"UPDATE settings SET config_imap_host = '$config_imap_host', config_imap_port = $config_imap_port, config_imap_encryption = '$config_imap_encryption', config_imap_username = '$config_imap_username', config_imap_password = '$config_imap_password' WHERE company_id = 1");
|
||||
// Standard IMAP fields (kept for all providers; OAuth still needs these endpoints)
|
||||
$config_imap_host = sanitizeInput($_POST['config_imap_host']);
|
||||
$config_imap_port = (int) sanitizeInput($_POST['config_imap_port']);
|
||||
$config_imap_encryption = sanitizeInput($_POST['config_imap_encryption']); // '', 'tls', 'ssl'
|
||||
$config_imap_username = sanitizeInput($_POST['config_imap_username']);
|
||||
$config_imap_password = sanitizeInput($_POST['config_imap_password']); // ignored if OAuth selected
|
||||
|
||||
logAction("Settings", "Edit", "$session_name edited IMAP mail settings");
|
||||
// Shared OAuth fields (may or may not be present in your form yet)
|
||||
$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
|
||||
|
||||
flash_alert("IMAP Mail Settings updated");
|
||||
// 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
|
||||
config_imap_provider = " . ($config_imap_provider !== '' ? $q($config_imap_provider) : "NULL") . ",
|
||||
config_imap_host = " . $q($config_imap_host) . ",
|
||||
config_imap_port = " . (int)$config_imap_port . ",
|
||||
config_imap_encryption = " . $q($config_imap_encryption) . ",
|
||||
config_imap_username = " . $q($config_imap_username) . ",
|
||||
config_imap_password = " . ($is_oauth ? "NULL" : $q($config_imap_password)) . ",
|
||||
|
||||
-- Shared OAuth fields (kept even if provider is Google or Microsoft; NULL if not used)
|
||||
config_mail_oauth_client_id = " . ($is_oauth ? $q($config_mail_oauth_client_id) : "NULL") . ",
|
||||
config_mail_oauth_client_secret = " . ($is_oauth ? $q($config_mail_oauth_client_secret) : "NULL") . ",
|
||||
config_mail_oauth_tenant_id = " . ($is_oauth ? $q($config_mail_oauth_tenant_id) : "NULL") . ",
|
||||
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
|
||||
";
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
redirect();
|
||||
|
||||
}
|
||||
|
||||
if (isset($_POST['edit_mail_from_settings'])) {
|
||||
|
|
|
|||
|
|
@ -84,37 +84,56 @@ require_once "includes/inc_all_admin.php";
|
|||
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP Host</label>
|
||||
<label>IMAP Provider</label>
|
||||
<div class="input-group">
|
||||
<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>
|
||||
<input type="text" class="form-control" name="config_imap_host" placeholder="Incoming Mail Server Address (for email to ticket parsing)" value="<?php echo nullable_htmlentities($config_imap_host); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP 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_imap_port" placeholder="Incoming Mail Server Port Number (993)" value="<?php echo intval($config_imap_port); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP 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_imap_encryption">
|
||||
<option value=''>None</option>
|
||||
<option <?php if ($config_imap_encryption == 'tls') { echo "selected"; } ?> value="tls">TLS</option>
|
||||
<option <?php if ($config_imap_encryption == 'ssl') { echo "selected"; } ?> value="ssl">SSL</option>
|
||||
<select class="form-control" name="config_imap_provider" id="config_imap_provider">
|
||||
<option value="none" <?php if($config_imap_provider ==='') echo 'selected'; ?>>None (Disabled)</option>
|
||||
<option value="standard_imap" <?php if(($config_imap_provider ?? 'standard_imap')==='standard_imap') echo 'selected'; ?>>Standard IMAP (Username/Password)</option>
|
||||
<option value="google_oauth" <?php if(($config_imap_provider ?? '')==='google_oauth') echo 'selected'; ?>>Google Workspace (OAuth)</option>
|
||||
<option value="microsoft_oauth" <?php if(($config_imap_provider ?? '')==='microsoft_oauth') echo 'selected'; ?>>Microsoft 365 (OAuth)</option>
|
||||
</select>
|
||||
</div>
|
||||
<small class="text-secondary d-block mt-1" id="imap_provider_hint">
|
||||
Select your mailbox provider. OAuth options ignore the IMAP password here.
|
||||
</small>
|
||||
</div>
|
||||
<div id="standard_fields" style="display:none;">
|
||||
<div class="form-group">
|
||||
<label>IMAP Host</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-server"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="config_imap_host" placeholder="Incoming Mail Server Address (for email to ticket parsing)" value="<?php echo nullable_htmlentities($config_imap_host); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP 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_imap_port" placeholder="Incoming Mail Server Port Number (993)" value="<?php echo intval($config_imap_port); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>IMAP 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_imap_encryption">
|
||||
<option value=''>None</option>
|
||||
<option <?php if ($config_imap_encryption == 'tls') { echo "selected"; } ?> value="tls">TLS</option>
|
||||
<option <?php if ($config_imap_encryption == 'ssl') { echo "selected"; } ?> value="ssl">SSL</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='form-group'>
|
||||
|
|
@ -123,25 +142,80 @@ require_once "includes/inc_all_admin.php";
|
|||
<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_imap_username' placeholder='Username' value="<?php
|
||||
echo nullable_htmlentities($config_imap_username); ?>" required>
|
||||
<input type='text' class='form-control' name='config_imap_username' placeholder='Username (email address)' value="<?php echo nullable_htmlentities($config_imap_username); ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='form-group'>
|
||||
<div class='form-group' id="imap_password_group">
|
||||
<label>IMAP 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_imap_password' placeholder='Password' value="<?php
|
||||
echo nullable_htmlentities($config_imap_password); ?>" autocomplete='new-password' required>
|
||||
<input type='password' class='form-control' data-toggle='password' name='config_imap_password' placeholder='Password (not used for OAuth)' value="<?php echo nullable_htmlentities($config_imap_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 id="oauth_fields" style="display:none;">
|
||||
<hr>
|
||||
<h5 class="mb-2">OAuth Settings</h5>
|
||||
<p class="text-secondary" id="oauth_hint">
|
||||
Configure OAuth credentials for the selected provider.
|
||||
</p>
|
||||
|
||||
<div class="form-group">
|
||||
<label>OAuth Client ID</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i class="fa fa-fw fa-id-badge"></i></span></div>
|
||||
<input type="text" class="form-control" name="config_mail_oauth_client_id"
|
||||
value="<?php echo nullable_htmlentities($config_mail_oauth_client_id ?? ''); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>OAuth Client Secret</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_mail_oauth_client_secret"
|
||||
value="<?php echo nullable_htmlentities($config_mail_oauth_client_secret ?? ''); ?>" 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 class="form-group" id="tenant_row" style="display:none;">
|
||||
<label>Tenant ID (Microsoft 365 only)</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i class="fa fa-fw fa-building"></i></span></div>
|
||||
<input type="text" class="form-control" name="config_mail_oauth_tenant_id"
|
||||
value="<?php echo nullable_htmlentities($config_mail_oauth_tenant_id ?? ''); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Refresh Token</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i class="fa fa-fw fa-sync-alt"></i></span></div>
|
||||
<textarea class="form-control" name="config_mail_oauth_refresh_token" rows="2"
|
||||
placeholder="Paste refresh token"><?php echo nullable_htmlentities($config_mail_oauth_refresh_token ?? ''); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Access Token (optional – will refresh if expired)</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text"><i class="fa fa-fw fa-shield-alt"></i></span></div>
|
||||
<textarea class="form-control" name="config_mail_oauth_access_token" rows="2"
|
||||
placeholder="Can be left blank; system refreshes using the refresh token"><?php echo nullable_htmlentities($config_mail_oauth_access_token ?? ''); ?></textarea>
|
||||
</div>
|
||||
<small class="text-secondary">
|
||||
Expires at: <?php echo !empty($config_mail_oauth_access_token_expires_at) ? htmlspecialchars($config_mail_oauth_access_token_expires_at) : 'n/a'; ?>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<button type="submit" name="edit_mail_imap_settings" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
|
||||
|
|
@ -327,5 +401,67 @@ require_once "includes/inc_all_admin.php";
|
|||
|
||||
<?php } ?>
|
||||
|
||||
<?php require_once "../includes/footer.php";
|
||||
<script>
|
||||
(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){
|
||||
if(!container) return;
|
||||
container.querySelectorAll('input, select, textarea').forEach(el => {
|
||||
el.disabled = !!disabled;
|
||||
});
|
||||
}
|
||||
|
||||
function toggleFields(){
|
||||
if(!sel) return;
|
||||
const v = sel.value || '';
|
||||
const isNone = v === '';
|
||||
const isStd = v === 'standard_imap';
|
||||
const isG = v === 'google_oauth';
|
||||
const isM = v === 'microsoft_oauth';
|
||||
const isOAuth = isG || isM;
|
||||
|
||||
// Show/hide containers
|
||||
if (pwdGrp) pwdGrp.style.display = isStd ? '' : 'none';
|
||||
if (oauthWrap) oauthWrap.style.display = isOAuth ? '' : 'none';
|
||||
if (standardWrap) standardWrap.style.display = isStd ? '' : 'none';
|
||||
if (tenantRow) tenantRow.style.display = isM ? '' : 'none';
|
||||
|
||||
// Disable inputs inside hidden sections to avoid accidental submission
|
||||
setDisabled(pwdGrp, !isStd);
|
||||
setDisabled(standardWrap, !isStd);
|
||||
setDisabled(oauthWrap, !isOAuth);
|
||||
|
||||
// Update hints
|
||||
if (providerHint) {
|
||||
providerHint.textContent = isNone
|
||||
? 'Choose a provider to reveal the relevant settings.'
|
||||
: isStd
|
||||
? 'Standard IMAP: provide host, port, encryption, username, and password.'
|
||||
: isG
|
||||
? 'Google Workspace OAuth: provide Client ID & Secret; paste the refresh token; username should be the mailbox address.'
|
||||
: 'Microsoft 365 OAuth: provide Client ID, Secret & Tenant ID; paste the refresh token; username should be the mailbox address.';
|
||||
}
|
||||
if (oauthHint) {
|
||||
oauthHint.textContent = isG
|
||||
? 'Google Workspace OAuth: Client ID & Secret from Google Cloud; Refresh token generated via OAuth consent.'
|
||||
: isM
|
||||
? 'Microsoft 365 OAuth: Client ID, Secret & Tenant ID from Entra ID; Refresh token generated via OAuth consent.'
|
||||
: 'Configure OAuth credentials for the selected provider.';
|
||||
}
|
||||
}
|
||||
|
||||
if (sel) {
|
||||
sel.addEventListener('change', toggleFields);
|
||||
toggleFields();
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
<?php require_once "../includes/footer.php";
|
||||
|
|
|
|||
|
|
@ -311,29 +311,217 @@ function addReply($from_email, $date, $subject, $ticket_number, $message, $attac
|
|||
}
|
||||
|
||||
/** ------------------------------------------------------------------
|
||||
* Webklex IMAP setup
|
||||
* OAuth helpers + provider guard
|
||||
* ------------------------------------------------------------------ */
|
||||
|
||||
// returns true if expires_at ('Y-m-d H:i:s') is in the past (or missing)
|
||||
function tokenExpired(?string $expires_at): bool {
|
||||
if (empty($expires_at)) return true;
|
||||
$ts = strtotime($expires_at);
|
||||
if ($ts === false) return true;
|
||||
// refresh a little early (60s) to avoid race
|
||||
return ($ts - 60) <= time();
|
||||
}
|
||||
|
||||
// very small form-encoded POST helper using curl
|
||||
function httpFormPost(string $url, array $fields): array {
|
||||
$ch = curl_init($url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||
$raw = curl_exec($ch);
|
||||
$err = curl_error($ch);
|
||||
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
return ['ok' => ($raw !== false && $code >= 200 && $code < 300), 'body' => $raw, 'code' => $code, 'err' => $err];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a valid access token for Google Workspace IMAP via refresh token if needed.
|
||||
* Uses settings: config_mail_oauth_client_id / _client_secret / _refresh_token / _access_token / _access_token_expires_at
|
||||
* Updates globals if refreshed (so later logging can reflect it if you want to persist).
|
||||
*/
|
||||
function getGoogleAccessToken(string $username): ?string {
|
||||
// pull from global settings variables you already load
|
||||
global $mysqli,
|
||||
$config_mail_oauth_client_id,
|
||||
$config_mail_oauth_client_secret,
|
||||
$config_mail_oauth_refresh_token,
|
||||
$config_mail_oauth_access_token,
|
||||
$config_mail_oauth_access_token_expires_at;
|
||||
|
||||
// If we have a not-expired token, use it
|
||||
if (!empty($config_mail_oauth_access_token) && !tokenExpired($config_mail_oauth_access_token_expires_at)) {
|
||||
return $config_mail_oauth_access_token;
|
||||
}
|
||||
|
||||
// Need to refresh?
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_refresh_token)) {
|
||||
// Nothing we can do
|
||||
return null;
|
||||
}
|
||||
|
||||
$resp = httpFormPost(
|
||||
'https://oauth2.googleapis.com/token',
|
||||
[
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'client_secret' => $config_mail_oauth_client_secret,
|
||||
'refresh_token' => $config_mail_oauth_refresh_token,
|
||||
'grant_type' => 'refresh_token',
|
||||
]
|
||||
);
|
||||
|
||||
if (!$resp['ok']) return null;
|
||||
|
||||
$json = json_decode($resp['body'], true);
|
||||
if (!is_array($json) || empty($json['access_token'])) return null;
|
||||
|
||||
// Calculate new expiry
|
||||
$expires_at = date('Y-m-d H:i:s', time() + (int)($json['expires_in'] ?? 3600));
|
||||
|
||||
// Update in-memory globals (and persist to DB)
|
||||
$config_mail_oauth_access_token = $json['access_token'];
|
||||
$config_mail_oauth_access_token_expires_at = $expires_at;
|
||||
|
||||
$at_esc = mysqli_real_escape_string($mysqli, $config_mail_oauth_access_token);
|
||||
$exp_esc = mysqli_real_escape_string($mysqli, $config_mail_oauth_access_token_expires_at);
|
||||
mysqli_query($mysqli, "UPDATE settings SET
|
||||
config_mail_oauth_access_token = '{$at_esc}',
|
||||
config_mail_oauth_access_token_expires_at = '{$exp_esc}'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
return $config_mail_oauth_access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a valid access token for Microsoft 365 IMAP via refresh token if needed.
|
||||
* Uses settings: config_mail_oauth_client_id / _client_secret / _tenant_id / _refresh_token / _access_token / _access_token_expires_at
|
||||
*/
|
||||
function getMicrosoftAccessToken(string $username): ?string {
|
||||
global $mysqli,
|
||||
$config_mail_oauth_client_id,
|
||||
$config_mail_oauth_client_secret,
|
||||
$config_mail_oauth_tenant_id,
|
||||
$config_mail_oauth_refresh_token,
|
||||
$config_mail_oauth_access_token,
|
||||
$config_mail_oauth_access_token_expires_at;
|
||||
|
||||
if (!empty($config_mail_oauth_access_token) && !tokenExpired($config_mail_oauth_access_token_expires_at)) {
|
||||
return $config_mail_oauth_access_token;
|
||||
}
|
||||
|
||||
if (empty($config_mail_oauth_client_id) || empty($config_mail_oauth_client_secret) || empty($config_mail_oauth_refresh_token) || empty($config_mail_oauth_tenant_id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$url = "https://login.microsoftonline.com/".rawurlencode($config_mail_oauth_tenant_id)."/oauth2/v2.0/token";
|
||||
|
||||
$resp = httpFormPost($url, [
|
||||
'client_id' => $config_mail_oauth_client_id,
|
||||
'client_secret' => $config_mail_oauth_client_secret,
|
||||
'refresh_token' => $config_mail_oauth_refresh_token,
|
||||
'grant_type' => 'refresh_token',
|
||||
// IMAP/SMTP scopes typically included at initial consent; not needed for refresh
|
||||
]);
|
||||
|
||||
if (!$resp['ok']) return null;
|
||||
|
||||
$json = json_decode($resp['body'], true);
|
||||
if (!is_array($json) || empty($json['access_token'])) return null;
|
||||
|
||||
$expires_at = date('Y-m-d H:i:s', time() + (int)($json['expires_in'] ?? 3600));
|
||||
|
||||
$config_mail_oauth_access_token = $json['access_token'];
|
||||
$config_mail_oauth_access_token_expires_at = $expires_at;
|
||||
|
||||
$at_esc = mysqli_real_escape_string($mysqli, $config_mail_oauth_access_token);
|
||||
$exp_esc = mysqli_real_escape_string($mysqli, $config_mail_oauth_access_token_expires_at);
|
||||
mysqli_query($mysqli, "UPDATE settings SET
|
||||
config_mail_oauth_access_token = '{$at_esc}',
|
||||
config_mail_oauth_access_token_expires_at = '{$exp_esc}'
|
||||
WHERE company_id = 1
|
||||
");
|
||||
|
||||
return $config_mail_oauth_access_token;
|
||||
}
|
||||
|
||||
// Provider from settings (may be NULL/empty to disable IMAP polling)
|
||||
$imap_provider = $config_imap_provider ?? '';
|
||||
if ($imap_provider === null) $imap_provider = '';
|
||||
|
||||
if ($imap_provider === '') {
|
||||
// IMAP disabled by admin: exit cleanly
|
||||
logApp("Cron-Email-Parser", "info", "IMAP polling skipped: provider not configured.");
|
||||
@unlink($lock_file_path);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------
|
||||
* Webklex IMAP setup (supports Standard / Google OAuth / Microsoft OAuth)
|
||||
* ------------------------------------------------------------------ */
|
||||
use Webklex\PHPIMAP\ClientManager;
|
||||
|
||||
$validate_cert = true; // or false based on your configuration
|
||||
$validate_cert = true;
|
||||
|
||||
// Defaults from settings (standard IMAP)
|
||||
$host = $config_imap_host;
|
||||
$port = (int)$config_imap_port;
|
||||
$encr = !empty($config_imap_encryption) ? $config_imap_encryption : null; // 'ssl'|'tls'|null
|
||||
$user = $config_imap_username;
|
||||
$pass = $config_imap_password;
|
||||
$auth = null; // 'oauth' for OAuth providers
|
||||
|
||||
if ($imap_provider === 'google_oauth') {
|
||||
$host = 'imap.gmail.com';
|
||||
$port = 993;
|
||||
$encr = 'ssl';
|
||||
$auth = 'oauth';
|
||||
$pass = getGoogleAccessToken($user);
|
||||
if (empty($pass)) {
|
||||
logApp("Cron-Email-Parser", "error", "Google OAuth: no usable access token (check refresh token/client credentials).");
|
||||
@unlink($lock_file_path);
|
||||
exit(1);
|
||||
}
|
||||
} elseif ($imap_provider === 'microsoft_oauth') {
|
||||
$host = 'outlook.office365.com';
|
||||
$port = 993;
|
||||
$encr = 'ssl';
|
||||
$auth = 'oauth';
|
||||
$pass = getMicrosoftAccessToken($user);
|
||||
if (empty($pass)) {
|
||||
logApp("Cron-Email-Parser", "error", "Microsoft OAuth: no usable access token (check refresh token/client credentials/tenant).");
|
||||
@unlink($lock_file_path);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
// standard_imap (username/password)
|
||||
if (empty($host) || empty($port) || empty($user)) {
|
||||
logApp("Cron-Email-Parser", "error", "Standard IMAP: missing host/port/username.");
|
||||
@unlink($lock_file_path);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$cm = new ClientManager();
|
||||
|
||||
$client = $cm->make([
|
||||
'host' => $config_imap_host,
|
||||
'port' => (int)$config_imap_port,
|
||||
'encryption' => !empty($config_imap_encryption) ? $config_imap_encryption : null, // 'ssl' | 'tls' | null
|
||||
'validate_cert' => (bool)$validate_cert,
|
||||
'username' => $config_imap_username,
|
||||
'password' => $config_imap_password,
|
||||
'protocol' => 'imap'
|
||||
]);
|
||||
$client = $cm->make(array_filter([
|
||||
'host' => $host,
|
||||
'port' => $port,
|
||||
'encryption' => $encr, // 'ssl' | 'tls' | null
|
||||
'validate_cert' => (bool)$validate_cert,
|
||||
'username' => $user, // full mailbox address (OAuth uses user as principal)
|
||||
'password' => $pass, // access token when $auth === 'oauth'
|
||||
'authentication' => $auth, // 'oauth' or null
|
||||
'protocol' => 'imap',
|
||||
]));
|
||||
|
||||
try {
|
||||
$client->connect();
|
||||
} catch (\Throwable $e) {
|
||||
echo "Error connecting to IMAP server: " . $e->getMessage();
|
||||
unlink($lock_file_path);
|
||||
@unlink($lock_file_path);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
13
db.sql
13
db.sql
|
|
@ -1,9 +1,9 @@
|
|||
/*M!999999\- enable the sandbox mode */
|
||||
-- MariaDB dump 10.19 Distrib 10.11.11-MariaDB, for debian-linux-gnu (x86_64)
|
||||
-- MariaDB dump 10.19 Distrib 10.11.14-MariaDB, for debian-linux-gnu (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: itflow_dev
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.11.11-MariaDB-0+deb12u1
|
||||
-- Server version 10.11.14-MariaDB-0+deb12u2
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
|
|
@ -1988,6 +1988,13 @@ CREATE TABLE `settings` (
|
|||
`config_smtp_password` varchar(200) DEFAULT NULL,
|
||||
`config_mail_from_email` varchar(200) DEFAULT NULL,
|
||||
`config_mail_from_name` varchar(200) DEFAULT NULL,
|
||||
`config_imap_provider` enum('standard_imap','google_oauth','microsoft_oauth') DEFAULT NULL,
|
||||
`config_mail_oauth_client_id` varchar(255) DEFAULT NULL,
|
||||
`config_mail_oauth_client_secret` varchar(255) DEFAULT NULL,
|
||||
`config_mail_oauth_tenant_id` varchar(255) DEFAULT NULL,
|
||||
`config_mail_oauth_refresh_token` text DEFAULT NULL,
|
||||
`config_mail_oauth_access_token` text DEFAULT NULL,
|
||||
`config_mail_oauth_access_token_expires_at` datetime DEFAULT NULL,
|
||||
`config_imap_host` varchar(200) DEFAULT NULL,
|
||||
`config_imap_port` int(5) DEFAULT NULL,
|
||||
`config_imap_encryption` varchar(200) DEFAULT NULL,
|
||||
|
|
@ -2758,4 +2765,4 @@ CREATE TABLE `vendors` (
|
|||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2025-08-28 11:43:32
|
||||
-- Dump completed on 2025-09-12 15:55:31
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@
|
|||
* It is used in conjunction with database_updates.php
|
||||
*/
|
||||
|
||||
DEFINE("LATEST_DATABASE_VERSION", "2.3.2");
|
||||
DEFINE("LATEST_DATABASE_VERSION", "2.3.3");
|
||||
|
|
|
|||
|
|
@ -21,12 +21,21 @@ $config_mail_from_email = $row['config_mail_from_email'];
|
|||
$config_mail_from_name = $row['config_mail_from_name'];
|
||||
|
||||
// Mail - IMAP
|
||||
$config_imap_provider = $row['config_imap_provider'];
|
||||
$config_imap_host = $row['config_imap_host'];
|
||||
$config_imap_port = intval($row['config_imap_port']);
|
||||
$config_imap_encryption = $row['config_imap_encryption'];
|
||||
$config_imap_username = $row['config_imap_username'];
|
||||
$config_imap_password = $row['config_imap_password'];
|
||||
|
||||
// Mail OAUTH2
|
||||
$config_mail_oauth_client_id = $row['config_mail_oauth_client_id'];
|
||||
$config_mail_oauth_client_secret = $row['config_mail_oauth_client_secret'];
|
||||
$config_mail_oauth_tenant_id = $row['config_mail_oauth_tenant_id'];
|
||||
$config_mail_oauth_refresh_token = $row['config_mail_oauth_refresh_token'];
|
||||
$config_mail_oauth_access_token = $row['config_mail_oauth_access_token'];
|
||||
$config_mail_oauth_access_token_expires_at = $row['config_mail_oauth_access_token_expires_at'];
|
||||
|
||||
// Defaults
|
||||
$config_start_page = $row['config_start_page'] ?? 'clients.php';
|
||||
$config_default_transfer_from_account = intval($row['config_default_transfer_from_account']);
|
||||
|
|
|
|||
Loading…
Reference in New Issue