forked from fa/breadcrumb-the-shire
Introduce per-tenant override for helpdesk BC connection config. New table helpdesk_tenant_settings stores tenant-specific credentials with encrypted secrets (AES-256-GCM). EffectiveHelpdeskSettingsService resolves global vs tenant config per request. Settings UI extended with tenant override tab, toggle, and dual editing mode. All runtime consumers (OData, SOAP, OAuth) read through the new resolver. Token cache flushed on any config change. Default behavior unchanged — tenants use global config until override explicitly enabled. Also includes risk radar UI refinements: Stripe-style card redesign with accent borders and score pills, removal of redundant KPI tiles and search, and filtering of zero-score entries. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 lines
2.4 KiB
PHP
88 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace MintyPHP\Module\Helpdesk\Service;
|
|
|
|
use MintyPHP\DB;
|
|
use MintyPHP\Service\Settings\SettingsCryptoGatewayInterface;
|
|
|
|
/**
|
|
* Repository for OAuth2 token cache (helpdesk_oauth_token_cache table).
|
|
*
|
|
* All tokens are stored encrypted and tenant-scoped.
|
|
* This is part of the OAuth2 skeleton for V1.
|
|
*/
|
|
class HelpdeskTokenRepository
|
|
{
|
|
public function __construct(
|
|
private readonly SettingsCryptoGatewayInterface $settingsCryptoGateway
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Find a valid (non-expired) cached token for the given tenant.
|
|
*/
|
|
public function findValidToken(int $tenantId): ?string
|
|
{
|
|
if ($tenantId <= 0) {
|
|
return null;
|
|
}
|
|
|
|
$result = DB::selectOne(
|
|
'SELECT access_token_encrypted FROM helpdesk_oauth_token_cache WHERE tenant_id = ? AND expires_at > NOW() ORDER BY created_at DESC LIMIT 1',
|
|
(string) $tenantId
|
|
);
|
|
|
|
if (!is_array($result) || !isset($result['access_token_encrypted'])) {
|
|
return null;
|
|
}
|
|
|
|
$encrypted = trim((string) $result['access_token_encrypted']);
|
|
if ($encrypted === '') {
|
|
return null;
|
|
}
|
|
|
|
try {
|
|
return $this->settingsCryptoGateway->decryptString($encrypted);
|
|
} catch (\Throwable) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete all cached tokens (used when BC config changes to prevent stale credentials).
|
|
*/
|
|
public function deleteAll(): bool
|
|
{
|
|
return (bool) DB::delete('DELETE FROM helpdesk_oauth_token_cache WHERE 1=1');
|
|
}
|
|
|
|
/**
|
|
* Store a new token in the cache (encrypted, tenant-scoped).
|
|
*/
|
|
public function storeToken(int $tenantId, string $accessToken, \DateTimeInterface $expiresAt): bool
|
|
{
|
|
if ($tenantId <= 0 || $accessToken === '') {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$encrypted = $this->settingsCryptoGateway->encryptString($accessToken);
|
|
} catch (\Throwable) {
|
|
return false;
|
|
}
|
|
|
|
// Remove existing tokens for this tenant first
|
|
DB::delete(
|
|
'DELETE FROM helpdesk_oauth_token_cache WHERE tenant_id = ?',
|
|
(string) $tenantId
|
|
);
|
|
|
|
return (bool) DB::insert(
|
|
'INSERT INTO helpdesk_oauth_token_cache (tenant_id, access_token_encrypted, expires_at) VALUES (?, ?, ?)',
|
|
(string) $tenantId,
|
|
$encrypted,
|
|
$expiresAt->format('Y-m-d H:i:s')
|
|
);
|
|
}
|
|
}
|