Absenderpruefung erweitern und Postfach auflisten koennen
Die Pruefung suchte woertlich nach "@paypal.de" oder "@paypal.com". Mails aus einer Versand-Subdomain (e.paypal.de) oder einer Landesvariante (paypal.at, paypal.co.uk) fielen damit als not_from_paypal durch. Geprueft wird jetzt die Domain der Absenderadresse an ihrem Ende - "paypal.de. beispiel.com" ist damit weiterhin kein PayPal, waere bei einer Textsuche aber durchgerutscht. check-imap-support.php listet zusaetzlich die letzten 15 Mails mit Absender, Empfaengerzeilen und Betreff auf und sagt je Mail, ob der Absender als PayPal gilt. Damit laesst sich ein not_from_paypal in einem Lauf klaeren statt zu raten. Rein lesend: OP_READONLY, kein \Seen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+26
-1
@@ -152,6 +152,31 @@ function paypal_match_participant(PDO $pdo, int $tenantId, string $payerName, ?s
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stammt die Mail wirklich von PayPal? Geprueft wird die Domain der
|
||||
* Absenderadresse - inklusive Landesvarianten (paypal.at, paypal.co.uk) und
|
||||
* Versand-Subdomains (e.paypal.de), die PayPal tatsaechlich benutzt.
|
||||
*
|
||||
* Der Vergleich haengt bewusst am Ende der Domain: "paypal.de.beispiel.com"
|
||||
* ist NICHT PayPal, wuerde bei einer simplen Textsuche nach "@paypal.de"
|
||||
* aber durchrutschen - und damit koennte jemand mit Kenntnis der
|
||||
* Eingangsadresse Zahlungen erfinden.
|
||||
*/
|
||||
function paypal_from_is_paypal(string $fromHeader): bool
|
||||
{
|
||||
if (!preg_match_all('/[\w.+-]+@([\w-]+(?:\.[\w-]+)+)/u', strtolower($fromHeader), $treffer)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($treffer[1] as $domain) {
|
||||
if (preg_match('/(^|\.)paypal\.[a-z]{2,}(\.[a-z]{2,})?$/', $domain)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gehoeren zwei Adressen zum selben Postfach? Plus-Adressierung wird dabei
|
||||
* ignoriert, "zahlungen+ab12cd@host" ist also dasselbe Postfach wie
|
||||
@@ -366,7 +391,7 @@ function paypal_preview(PDO $pdo, int $tenantId, array $parsed): array
|
||||
*/
|
||||
function paypal_process_raw(PDO $pdo, string $recipient, string $fromHeader, string $rawBody, bool $previewOnly = false): array
|
||||
{
|
||||
if (!preg_match('/@paypal\.(de|com)/i', $fromHeader)) {
|
||||
if (!paypal_from_is_paypal($fromHeader)) {
|
||||
return ['status' => 'not_from_paypal'];
|
||||
}
|
||||
$token = paypal_inbox_extract_token($recipient);
|
||||
|
||||
@@ -26,6 +26,8 @@ if (PHP_SAPI !== 'cli') {
|
||||
}
|
||||
|
||||
require_once __DIR__ . '/../app/bootstrap.php';
|
||||
// paypal_from_is_paypal() fuer die Absenderpruefung in der Auflistung.
|
||||
require_once __DIR__ . '/../app/paypal-inbox.php';
|
||||
|
||||
function imap_check_line(string $label, string $value): void
|
||||
{
|
||||
@@ -166,6 +168,43 @@ imap_check_line('davon ungelesen', (string) $ungelesen);
|
||||
fwrite($sock, "a9 LOGOUT\r\n");
|
||||
fclose($sock);
|
||||
|
||||
// Mit der Erweiterung laesst sich zusaetzlich auflisten, was im Postfach
|
||||
// liegt - die haeufigste Frage bei einer nicht verarbeiteten Mail ist "wer
|
||||
// war der Absender und an welche Adresse ging sie?". Rein lesend:
|
||||
// imap_fetch_overview() und imap_fetchheader() setzen kein \Seen.
|
||||
if (function_exists('imap_open')) {
|
||||
echo "\n=== Postfachinhalt (nur lesend, letzte 15) ===\n";
|
||||
$mbox = @imap_open('{' . $host . ':' . $port . $flags . '}' . $mailbox, $user, $pass, OP_READONLY);
|
||||
if ($mbox === false) {
|
||||
echo 'Zugriff ueber die imap-Erweiterung fehlgeschlagen: ' . imap_last_error() . "\n";
|
||||
} else {
|
||||
$anzahl = imap_num_msg($mbox);
|
||||
$von = max(1, $anzahl - 14);
|
||||
for ($msgno = $von; $msgno <= $anzahl; $msgno++) {
|
||||
$overview = imap_fetch_overview($mbox, (string) $msgno, 0)[0] ?? null;
|
||||
if ($overview === null) {
|
||||
continue;
|
||||
}
|
||||
$kopf = imap_fetchheader($mbox, $msgno);
|
||||
$empfaenger = [];
|
||||
if (preg_match_all('/^(?:Delivered-To|X-Original-To|To|X-Forwarded-To):\s*(.+)$/im', $kopf, $alle)) {
|
||||
$empfaenger = array_map('trim', $alle[1]);
|
||||
}
|
||||
$from = (string) ($overview->from ?? '');
|
||||
printf(
|
||||
"#%-3d %s Von: %s\n An: %s\n Betreff: %s\n Absender gilt als PayPal: %s\n",
|
||||
$msgno,
|
||||
(int) ($overview->seen ?? 0) === 1 ? 'gelesen ' : 'UNGELESEN',
|
||||
$from,
|
||||
implode(' | ', $empfaenger) !== '' ? implode(' | ', $empfaenger) : '(keine Empfaengerzeile gefunden)',
|
||||
(string) ($overview->subject ?? ''),
|
||||
paypal_from_is_paypal($from) ? 'ja' : 'NEIN - deshalb not_from_paypal'
|
||||
);
|
||||
}
|
||||
imap_close($mbox);
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nErgebnis: Postfach erreichbar und Zugangsdaten gueltig.\n";
|
||||
if (function_exists('imap_open')) {
|
||||
echo "Die imap-Erweiterung ist vorhanden - scripts/fetch-paypal-payments.php\n"
|
||||
|
||||
@@ -234,6 +234,27 @@ try {
|
||||
$fremd = paypal_process_raw($pdo, $empfaengerA, 'no-reply@beispiel.de', $mailA);
|
||||
paypal_flow_assert('Mail von fremdem Absender wird abgelehnt', ($fremd['status'] ?? '') === 'not_from_paypal', $failures, $passes);
|
||||
|
||||
// Absenderpruefung: PayPal verschickt aus mehreren Domains, eine
|
||||
// Lookalike-Domain darf aber nie durchgehen.
|
||||
foreach ([
|
||||
'"PayPal" <service@paypal.de>' => true,
|
||||
'service@paypal.com' => true,
|
||||
'PayPal <service@e.paypal.de>' => true,
|
||||
'noreply@paypal.at' => true,
|
||||
'service@paypal.co.uk' => true,
|
||||
'betrug@paypal.de.beispiel.com' => false,
|
||||
'paypal@beispiel.de' => false,
|
||||
'clemens@beispiel.de' => false,
|
||||
'' => false,
|
||||
] as $absender => $erwartet) {
|
||||
paypal_flow_assert(
|
||||
'Absender "' . ($absender === '' ? '(leer)' : $absender) . '" gilt ' . ($erwartet ? 'als' : 'nicht als') . ' PayPal',
|
||||
paypal_from_is_paypal($absender) === $erwartet,
|
||||
$failures,
|
||||
$passes
|
||||
);
|
||||
}
|
||||
|
||||
$ohneToken = paypal_process_raw($pdo, 'zahlungen@kaffeeliste.de', 'service@paypal.de', $mailA);
|
||||
paypal_flow_assert('Adresse ohne Token wird abgelehnt', ($ohneToken['status'] ?? '') === 'no_token', $failures, $passes);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user