mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-31 00:57:11 +09:00
* refactor(mail): replace phpmailer with symfony mailer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * style(codex): fix coding standards in Symfony Mailer migration Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(codex): fix TLS downgrade bug and From address overwrite in Symfony Mailer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(codex): guard SMTP stream setTimeout calls behind SocketStream check setTimeout() exists on SocketStream only; getStream() is typed AbstractStream, which fails PHPStan level 6. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(codex): correct inline graph CID, mandatory STARTTLS, and address validation in Symfony Mailer Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(codex): test inline CID, STARTTLS enforcement, and address-error handling Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): qualify bare local addresses so sendmail recipients still work Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): prune the stale PHPMailer vendor tree on upgrade Replacing PHPMailer with Symfony Mailer dropped phpmailer from composer.json, but the change also removed the prune_deprecated_files entries that cleaned up the vendored tree, so an upgraded install would keep stale PHPMailer code on disk. Add include/vendor/phpmailer (whole directory) to the prune list. Co-Authored-By: Oz <oz-agent@warp.dev> Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): address transport review feedback Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): drop setAutoTls() call missing from symfony/mailer 6.4 EsmtpTransport::setAutoTls() only exists in symfony/mailer >= 7.1, and the 6.4 series (needed for PHP 8.1) has no switch to disable opportunistic STARTTLS, so hide the advertised capability in a small subclass instead. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): vendor the psr/log 1.1.4 sources include/vendor/psr/log was tracked with only its package metadata, so composer treats it as installed and never extracts the classes. That was harmless while nothing loaded them, but Symfony Mailer's AbstractTransport instantiates Psr\Log\NullLogger on every transport, which now fatals at runtime and in the test job. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(mail): match PHPMailer SMTP and attachment semantics Empty secure modes use no-STARTTLS transport; inline disposition is honoured; unreadable attachments fail closed. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomas@vincent.dev> Co-authored-by: Oz <oz-agent@warp.dev>
70 lines
2.7 KiB
PHP
70 lines
2.7 KiB
PHP
<?php
|
|
declare(strict_types = 1);
|
|
/*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
| |
|
|
| This program is free software; you can redistribute it and/or |
|
|
| modify it under the terms of the GNU General Public License |
|
|
| as published by the Free Software Foundation; either version 2 |
|
|
| of the License, or (at your option) any later version. |
|
|
+-------------------------------------------------------------------------+
|
|
| Cacti: The Complete RRDtool-based Graphing Solution |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
use Symfony\Component\Mailer\Exception\TransportException;
|
|
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport;
|
|
use Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream;
|
|
|
|
/**
|
|
* EsmtpTransport that requires STARTTLS.
|
|
*
|
|
* The base EsmtpTransport only upgrades to STARTTLS when the server advertises
|
|
* it, so a server that omits the capability is talked to in plaintext. This
|
|
* matches PHPMailer's mandatory-STARTTLS behaviour: after the connection is
|
|
* established the stream must be encrypted, otherwise the send fails closed.
|
|
* This Symfony release has no setRequireTls(), so the check is done here.
|
|
*/
|
|
class CactiRequireTlsEsmtpTransport extends EsmtpTransport {
|
|
public function start(): void {
|
|
parent::start();
|
|
|
|
$stream = $this->getStream();
|
|
|
|
// After EHLO, an advertised STARTTLS leaves the stream encrypted. A
|
|
// plaintext stream here means the server never offered STARTTLS.
|
|
if ($stream instanceof SocketStream && !$stream->isTLS()) {
|
|
$this->stop();
|
|
|
|
throw new TransportException('STARTTLS is required but the SMTP server did not offer it.');
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* EsmtpTransport that never upgrades to STARTTLS.
|
|
*
|
|
* The base EsmtpTransport upgrades to STARTTLS whenever the server advertises
|
|
* it, even when no encryption was requested. This matches PHPMailer's
|
|
* SMTPAutoTLS = false behaviour for the 'none' security mode: the STARTTLS
|
|
* capability is stripped from the EHLO response before the base class can act
|
|
* on it. This Symfony release has no setAutoTls(), so the filtering is done
|
|
* here.
|
|
*/
|
|
class CactiNoTlsEsmtpTransport extends EsmtpTransport {
|
|
/**
|
|
* @param int[] $codes
|
|
*/
|
|
public function executeCommand(string $command, array $codes): string {
|
|
$response = parent::executeCommand($command, $codes);
|
|
|
|
// Hide the STARTTLS capability so the base class never upgrades.
|
|
if (str_starts_with($command, 'EHLO ')) {
|
|
$response = preg_replace('/^\d{3}[ -]STARTTLS\r\n/mi', '', $response) ?? $response;
|
|
}
|
|
|
|
return $response;
|
|
}
|
|
}
|