diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6455625..daf41cc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ["5.4", "5.5", "5.6", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5"] + php-version: ["7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2", "8.3", "8.4", "8.5"] experimental: [false] composer-options: [''] include: diff --git a/README.md b/README.md index d0a04f0..5c646df 100644 --- a/README.md +++ b/README.md @@ -25,8 +25,8 @@ The plugin name to add to your config file is: `tls_icon`. ## Requirements -- Roundcube `1.3.0` or newer. -- PHP `5.4` or newer. +- Roundcube `1.3.0` or newer (tested up to 1.7). +- PHP `7.1` or newer. ## Currently supported languages diff --git a/composer.json b/composer.json index 1c3938a..abe5972 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ } ], "require": { - "php": "^5.4 || ^7.0 || ^8.0", + "php": "^7.1 || ^8.0", "roundcube/plugin-installer": ">=0.1.6" }, "config": { diff --git a/test/TlsIconTest.php b/test/TlsIconTest.php index b50e545..73a72ae 100644 --- a/test/TlsIconTest.php +++ b/test/TlsIconTest.php @@ -13,38 +13,61 @@ final class TlsIconTest extends TestCase { /** @var string */ - private $strUnEnCrypted = ''; + private $strUnEnCrypted; /** @var string */ - private $strCryptedTlsv12 = ''; + private $strCryptedTlsv12; /** @var string */ - private $strCryptedTlsv12WithCipher = ''; + private $strCryptedTlsv12WithCipher; /** @var string */ - private $strInternal = ''; + private $strInternal; /** @var string */ - private $strSendmailCryptedTlsv13WithCipherNoVerify = ''; + private $strSendmailCryptedTlsv13WithCipherNoVerify; /** @var string */ - private $strSendmailCryptedTlsv12WithCipherVerify = ''; + private $strSendmailCryptedTlsv12WithCipherVerify; /** @var string */ - private $strStalwartCryptedTlsv13WithCipher = ''; + private $strStalwartCryptedTlsv13WithCipher; /** @var string */ - private $strNewPostfixTLSv13 = ''; + private $strNewPostfixTLSv13; + + public function __construct($name = null, array $data = [], $dataName = '') + { + parent::__construct($name, $data, $dataName); + $plugin = new tls_icon(); + $plugin->init(); + $this->strUnEnCrypted = ''; + $this->strCryptedTlsv12 = ''; + $this->strCryptedTlsv12WithCipher = ''; + $this->strInternal = ''; + $this->strSendmailCryptedTlsv13WithCipherNoVerify = ''; + $this->strSendmailCryptedTlsv12WithCipherVerify = ''; + $this->strStalwartCryptedTlsv13WithCipher = ''; + $this->strNewPostfixTLSv13 = ''; + } + + protected function tearDown(): void + { + rcmail::$instance = null; + parent::tearDown(); + } public function testInstance() { $o = new tls_icon(); + $o->init(); $this->assertInstanceOf('tls_icon', $o); } public function testStorage_Init() { $o = new tls_icon(); + $o->init(); $this->assertSame([ 'fetch_headers' => 'RECEIVED' ], $o->storage_init([])); @@ -62,19 +85,21 @@ public function testStorage_Init() public function testMessageHeadersNothing() { $o = new tls_icon(); + $o->init(); $this->assertSame([], $o->message_headers([])); } public function testMessageHeadersNoMatching() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'my header', ] @@ -87,7 +112,7 @@ public function testMessageHeadersNoMatching() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'my header', ] @@ -98,18 +123,19 @@ public function testMessageHeadersNoMatching() public function testMessageHeadersTlsWithCipher() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-21.smtp.github.com [192.30.252.204]) - (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) - by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 - for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) + by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 + for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', ] ] ]); @@ -120,12 +146,12 @@ public function testMessageHeadersTlsWithCipher() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-21.smtp.github.com [192.30.252.204]) - (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) - by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 - for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) + by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 + for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', ] ] ], $headersProcessed); @@ -134,18 +160,19 @@ public function testMessageHeadersTlsWithCipher() public function testMessageHeadersTls() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-21.smtp.github.com [192.30.252.204]) - (using TLSv1.2) (No client certificate requested) - by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 - for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', + (using TLSv1.2) (No client certificate requested) + by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 + for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', ] ] ]); @@ -156,12 +183,12 @@ public function testMessageHeadersTls() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-21.smtp.github.com [192.30.252.204]) - (using TLSv1.2) (No client certificate requested) - by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 - for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', + (using TLSv1.2) (No client certificate requested) + by mail.example.org (Postfix) with ESMTPS id 46B4C497C2 + for ; Sat, 9 Jul 2022 14:03:01 +0000 (UTC)', ] ] ], $headersProcessed); @@ -170,16 +197,17 @@ public function testMessageHeadersTls() public function testMessageHeadersInternal() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'by aaa.bbb.ccc (Postfix, from userid 0) - id A70248414D5; Sun, 26 Apr 2020 16:49:01 +0200 (CEST)', + id A70248414D5; Sun, 26 Apr 2020 16:49:01 +0200 (CEST)', ] ] ]); @@ -190,10 +218,10 @@ public function testMessageHeadersInternal() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'by aaa.bbb.ccc (Postfix, from userid 0) - id A70248414D5; Sun, 26 Apr 2020 16:49:01 +0200 (CEST)', + id A70248414D5; Sun, 26 Apr 2020 16:49:01 +0200 (CEST)', ] ] ], $headersProcessed); @@ -203,16 +231,17 @@ public function testMessageHeadersInternal() public function testMessageHeadersInternalLocalhostIPv4() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mail.whitequark.org (localhost [127.0.0.1]) - by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', + by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', ] ] ]); @@ -223,10 +252,10 @@ public function testMessageHeadersInternalLocalhostIPv4() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mail.whitequark.org (localhost [127.0.0.1]) - by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', + by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', ] ] ], $headersProcessed); @@ -235,16 +264,17 @@ public function testMessageHeadersInternalLocalhostIPv4() public function testMessageHeadersInternalLocalhostIPv6() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mail.whitequark.org (localhost [IPv6:::1]) - by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', + by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', ] ] ]); @@ -255,10 +285,10 @@ public function testMessageHeadersInternalLocalhostIPv6() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mail.whitequark.org (localhost [IPv6:::1]) - by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', + by mail.whitequark.org (Postfix) with ESMTP id CDCA2E08B7', ] ] ], $headersProcessed); @@ -273,13 +303,14 @@ public function testPostfixTLS13NewSyntax() for ; Tue, 16 Sep 2025 12:26:17 +0200 (CEST)'; $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $header, ] @@ -292,7 +323,7 @@ public function testPostfixTLS13NewSyntax() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $header, ] @@ -319,7 +350,7 @@ public function testMessageHeadersMultiFromWithConfig() 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $inputHeaders, ] @@ -332,7 +363,7 @@ public function testMessageHeadersMultiFromWithConfig() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $inputHeaders, ] @@ -358,7 +389,7 @@ public function testMessageHeadersMultiFromWithBadConfig() 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $inputHeaders, ] @@ -371,7 +402,7 @@ public function testMessageHeadersMultiFromWithBadConfig() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => $inputHeaders, ] @@ -382,18 +413,19 @@ public function testMessageHeadersMultiFromWithBadConfig() public function testSendmailTLS13NoVerify() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from 69-171-232-143.mail-mail.facebook.com (69-171-232-143.mail-mail.facebook.com [69.171.232.143]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BI73F8b1489360 - (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO) - for ; Sun, 18 Dec 2022 07:03:16 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BI73F8b1489360 + (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO) + for ; Sun, 18 Dec 2022 07:03:16 GMT', ] ] ]); @@ -404,12 +436,12 @@ public function testSendmailTLS13NoVerify() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from 69-171-232-143.mail-mail.facebook.com (69-171-232-143.mail-mail.facebook.com [69.171.232.143]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BI73F8b1489360 - (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO) - for ; Sun, 18 Dec 2022 07:03:16 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BI73F8b1489360 + (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO) + for ; Sun, 18 Dec 2022 07:03:16 GMT', ] ] ], $headersProcessed); @@ -418,18 +450,19 @@ public function testSendmailTLS13NoVerify() public function testSendmailTLS12WithVerify() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-18.smtp.github.com [192.30.252.201]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BGMf4uY685293 - (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) - for ; Fri, 16 Dec 2022 22:41:05 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BGMf4uY685293 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) + for ; Fri, 16 Dec 2022 22:41:05 GMT', ] ] ]); @@ -440,12 +473,12 @@ public function testSendmailTLS12WithVerify() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from smtp.github.com (out-18.smtp.github.com [192.30.252.201]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BGMf4uY685293 - (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) - for ; Fri, 16 Dec 2022 22:41:05 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BGMf4uY685293 + (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK) + for ; Fri, 16 Dec 2022 22:41:05 GMT', ] ] ], $headersProcessed); @@ -454,18 +487,19 @@ public function testSendmailTLS12WithVerify() public function testSendmailTLS13MultipleRecipients() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ 'value' => 'Sent to you', ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mout.kundenserver.de (mout.kundenserver.de [212.227.126.134]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BLGrgYw3602565 - (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); - Wed, 21 Dec 2022 16:53:42 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BLGrgYw3602565 + (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); + Wed, 21 Dec 2022 16:53:42 GMT', ] ] ]); @@ -476,12 +510,12 @@ public function testSendmailTLS13MultipleRecipients() 'html' => 1, ], ], - 'headers' => (object)[ + 'headers' => (object) [ 'others' => [ 'received' => 'from mout.kundenserver.de (mout.kundenserver.de [212.227.126.134]) - by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BLGrgYw3602565 - (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); - Wed, 21 Dec 2022 16:53:42 GMT', + by mail.aegee.org (8.17.1/8.17.1) with ESMTPS id 2BLGrgYw3602565 + (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); + Wed, 21 Dec 2022 16:53:42 GMT', ] ] ], $headersProcessed); @@ -490,6 +524,7 @@ public function testSendmailTLS13MultipleRecipients() public function testStalwartTls() { $o = new tls_icon(); + $o->init(); $headersProcessed = $o->message_headers([ 'output' => [ 'subject' => [ @@ -499,9 +534,9 @@ public function testStalwartTls() 'headers' => (object) [ 'others' => [ 'received' => 'from mail-yw1-f174.google.com (mail-yw1-f174.google.com [209.85.128.174] (AS15169 Google LLC, US)) - (using TLSv1.3 with cipher TLS13_AES_256_GCM_SHA384) - by mail.example.org (Stalwart SMTP) with ESMTPS id 36DAF29F3A02098; - Mon, 16 Jun 2025 13:33:03 +0000', + (using TLSv1.3 with cipher TLS13_AES_256_GCM_SHA384) + by mail.example.org (Stalwart SMTP) with ESMTPS id 36DAF29F3A02098; + Mon, 16 Jun 2025 13:33:03 +0000', ] ] ]); @@ -515,11 +550,65 @@ public function testStalwartTls() 'headers' => (object) [ 'others' => [ 'received' => 'from mail-yw1-f174.google.com (mail-yw1-f174.google.com [209.85.128.174] (AS15169 Google LLC, US)) - (using TLSv1.3 with cipher TLS13_AES_256_GCM_SHA384) - by mail.example.org (Stalwart SMTP) with ESMTPS id 36DAF29F3A02098; - Mon, 16 Jun 2025 13:33:03 +0000', + (using TLSv1.3 with cipher TLS13_AES_256_GCM_SHA384) + by mail.example.org (Stalwart SMTP) with ESMTPS id 36DAF29F3A02098; + Mon, 16 Jun 2025 13:33:03 +0000', ] ] ], $headersProcessed); } + + public function testAssetUrlStubCanReturnLegacyPath() + { + $rcmail = rcmail::get_instance(); + $rcmail->output->set_asset_url_callback(function ($path) { + return 'plugins/tls_icon/' . basename($path); + }); + + $plugin = new tls_icon(); + $plugin->init(); + $this->assertSame('plugins/tls_icon/lock.svg', $plugin->get_svg_path('lock.svg')); + } + + public function testAssetUrlStubCanReturnStaticPhpPath() + { + $rcmail = rcmail::get_instance(); + $rcmail->output->set_asset_url_callback(function ($path) { + return 'static.php/' . $path; + }); + + $plugin = new tls_icon(); + $plugin->init(); + $this->assertSame('static.php/plugins/tls_icon/lock.svg', $plugin->get_svg_path('lock.svg')); + } + + public function testMessageHeadersUsesStaticPhpAssetUrl() + { + $rcmail = rcmail::get_instance(); + $rcmail->output->set_asset_url_callback(function ($path) { + return 'static.php/' . $path; + }); + + $plugin = new tls_icon(); + $plugin->init(); + + $headersProcessed = $plugin->message_headers([ + 'output' => [ + 'subject' => [ + 'value' => 'Sent to you', + ], + ], + 'headers' => (object) [ + 'others' => [ + 'received' => 'from mail-yw1-f174.google.com (mail-yw1-f174.google.com [209.85.128.174] (AS15169 Google LLC, US)) + (using TLSv1.3 with cipher TLS13_AES_256_GCM_SHA384) + by mail.example.org (Stalwart SMTP) with ESMTPS id 36DAF29F3A02098; + Mon, 16 Jun 2025 13:33:03 +0000', + ] + ] + ]); + + $this->assertSame(1, $headersProcessed['output']['subject']['html']); + $this->assertStringContainsString('src="static.php/plugins/tls_icon/lock.svg"', $headersProcessed['output']['subject']['value']); + } } diff --git a/test/rcmail.php b/test/rcmail.php index c3e8052..d05b40a 100644 --- a/test/rcmail.php +++ b/test/rcmail.php @@ -4,22 +4,53 @@ /** * @internal Test class that does not exist anywhere */ -class rcmail_config { +class rcmail_config +{ private $data = []; - public function get($keyname) { + public function get($keyname) + { return $this->data[$keyname]; } /** * @internal added method for testing purposes */ - public function set($keyname, $value) { + public function set($keyname, $value) + { $this->data[$keyname] = $value; } } +/** + * @internal Test class to mock Roundcube output handling + */ +class rcmail_output +{ + /** + * @var callable|null + */ + private $asset_url_callback = null; + + public function asset_url($path) + { + if ($this->asset_url_callback !== null) { + return call_user_func($this->asset_url_callback, $path); + } + + return $path; + } + + /** + * @internal added method for testing purposes + */ + public function set_asset_url_callback($callback) + { + $this->asset_url_callback = $callback; + } +} + /** * @internal Test class to mock Roundcube */ @@ -30,6 +61,11 @@ class rcmail */ public $config; + /** + * @var rcmail_output + */ + public $output; + /** * @var self|null */ @@ -38,9 +74,11 @@ class rcmail public function __construct() { $this->config = new rcmail_config(); + $this->output = new rcmail_output(); } - public static function get_instance() { + public static function get_instance() + { if (static::$instance === null) { static::$instance = new self(); } diff --git a/tls_icon.php b/tls_icon.php index 4a17f33..a8deba6 100644 --- a/tls_icon.php +++ b/tls_icon.php @@ -46,6 +46,11 @@ public function storage_init($p) return $p; } + public function get_svg_path($filename) + { + return $this->rcmail->output->asset_url('plugins/tls_icon/' . $filename); + } + public function message_headers($p) { if ($this->message_headers_done === false) { @@ -64,11 +69,11 @@ public function message_headers($p) preg_match_all(tls_icon::SENDMAIL_TLS_REGEX, $Received, $items, PREG_PATTERN_ORDER) ) { $data = $items[1][0]; - $this->icon_img .= ''; + $this->icon_img .= ''; } elseif (preg_match_all(tls_icon::POSTFIX_LOCAL_REGEX, $Received, $items, PREG_PATTERN_ORDER)) { - $this->icon_img .= ''; + $this->icon_img .= ''; } else { - $this->icon_img .= ''; + $this->icon_img .= ''; } }