Passed
Push — master ( eabf67...a606bb )
by Alexander
07:46
created

EmailTest   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 199
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 130
dl 0
loc 199
rs 10
c 2
b 0
f 0
wmc 9
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Tests\Rule;
6
7
use PHPUnit\Framework\TestCase;
8
use Yiisoft\Validator\Rule\Email;
9
10
/**
11
 * @group validators
12
 */
13
class EmailTest extends TestCase
14
{
15
    public function testValidate(): void
16
    {
17
        $validator = new Email();
18
19
        $this->assertTrue($validator->validate('[email protected]')->isValid());
20
        $this->assertTrue($validator->validate('[email protected]')->isValid());
21
        $this->assertTrue($validator->validate('[email protected]')->isValid());
22
        $this->assertTrue($validator->validate('user+mailbox/[email protected]')->isValid());
23
        $this->assertTrue($validator->validate('!#$%&\'*+-/=?^_`.{|}[email protected]')->isValid());
24
        $this->assertFalse($validator->validate('rmcreative.ru')->isValid());
25
        $this->assertFalse($validator->validate('Carsten Brandt <[email protected]>')->isValid());
26
        $this->assertFalse($validator->validate('"Carsten Brandt" <[email protected]>')->isValid());
27
        $this->assertFalse($validator->validate('<[email protected]>')->isValid());
28
        $this->assertFalse($validator->validate('info@örtliches.de')->isValid());
29
        $this->assertFalse($validator->validate('sam@рмкреатиф.ru')->isValid());
30
        $this->assertFalse($validator->validate('[email protected]')->isValid());
31
        $this->assertFalse($validator->validate(['[email protected]'])->isValid());
32
33
        $validator = $validator->allowName(true);
34
35
        $this->assertTrue($validator->validate('[email protected]')->isValid());
36
        $this->assertTrue($validator->validate('[email protected]')->isValid());
37
        $this->assertFalse($validator->validate('rmcreative.ru')->isValid());
38
        $this->assertTrue($validator->validate('Carsten Brandt <[email protected]>')->isValid());
39
        $this->assertTrue($validator->validate('"Carsten Brandt" <[email protected]>')->isValid());
40
        $this->assertTrue($validator->validate('<[email protected]>')->isValid());
41
        $this->assertFalse($validator->validate('info@örtliches.de')->isValid());
42
        $this->assertFalse($validator->validate('üñîçøðé@üñîçøðé.com')->isValid());
43
        $this->assertFalse($validator->validate('sam@рмкреатиф.ru')->isValid());
44
        $this->assertFalse($validator->validate('Informtation [email protected]')->isValid());
45
        $this->assertTrue($validator->validate('[email protected]')->isValid());
46
        $this->assertTrue($validator->validate('John Smith <[email protected]>')->isValid());
47
        $this->assertTrue(
48
            $validator->validate(
49
                '"This name is longer than 64 characters. Blah blah blah blah blah" <[email protected]>'
50
            )->isValid()
51
        );
52
        $this->assertFalse($validator->validate('John Smith <example.com>')->isValid());
53
        $this->assertFalse(
54
            $validator->validate(
55
                'Short Name <localPartMoreThan64Characters-blah-blah-blah-blah-blah-blah-blah-blah@example.com>'
56
            )->isValid()
57
        );
58
        $this->assertFalse(
59
            $validator->validate(
60
                'Short Name <domainNameIsMoreThan254Characters@example-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah.com>'
61
            )->isValid()
62
        );
63
        $this->assertFalse($validator->validate(['[email protected]'])->isValid());
64
    }
65
66
    public function testValidateIdn(): void
67
    {
68
        if (!function_exists('idn_to_ascii')) {
69
            $this->markTestSkipped('Intl extension required');
70
71
            return;
72
        }
73
        $validator = (new Email())
74
            ->enableIDN(true);
75
76
        $this->assertTrue($validator->validate('[email protected]')->isValid());
77
        $this->assertTrue($validator->validate('example@äüößìà.de')->isValid());
78
        $this->assertTrue($validator->validate('[email protected]')->isValid());
79
        $this->assertTrue($validator->validate('info@örtliches.de')->isValid());
80
        $this->assertTrue($validator->validate('sam@рмкреатиф.ru')->isValid());
81
        $this->assertTrue($validator->validate('[email protected]')->isValid());
82
        $this->assertTrue($validator->validate('[email protected]')->isValid());
83
        $this->assertTrue($validator->validate('üñîçøðé@üñîçøðé.com')->isValid());
84
        $this->assertFalse($validator->validate('rmcreative.ru')->isValid());
85
        $this->assertFalse($validator->validate('Carsten Brandt <[email protected]>')->isValid());
86
        $this->assertFalse($validator->validate('"Carsten Brandt" <[email protected]>')->isValid());
87
        $this->assertFalse($validator->validate('<[email protected]>')->isValid());
88
89
        $validator = $validator->allowName(true);
90
91
        $this->assertTrue($validator->validate('info@örtliches.de')->isValid());
92
        $this->assertTrue($validator->validate('Informtation <info@örtliches.de>')->isValid());
93
        $this->assertFalse($validator->validate('Informtation info@örtliches.de')->isValid());
94
        $this->assertTrue($validator->validate('sam@рмкреатиф.ru')->isValid());
95
        $this->assertTrue($validator->validate('[email protected]')->isValid());
96
        $this->assertTrue($validator->validate('[email protected]')->isValid());
97
        $this->assertFalse($validator->validate('rmcreative.ru')->isValid());
98
        $this->assertTrue($validator->validate('Carsten Brandt <[email protected]>')->isValid());
99
        $this->assertTrue($validator->validate('"Carsten Brandt" <[email protected]>')->isValid());
100
        $this->assertTrue($validator->validate('üñîçøðé 日本国 <üñîçøðé@üñîçøðé.com>')->isValid());
101
        $this->assertTrue($validator->validate('<[email protected]>')->isValid());
102
        $this->assertTrue($validator->validate('[email protected]')->isValid());
103
        $this->assertTrue($validator->validate('John Smith <[email protected]>')->isValid());
104
        $this->assertTrue(
105
            $validator->validate(
106
                '"Такое имя достаточно длинное, но оно все равно может пройти валидацию" <[email protected]>'
107
            )->isValid()
108
        );
109
        $this->assertFalse($validator->validate('John Smith <example.com>')->isValid());
110
        $this->assertFalse(
111
            $validator->validate(
112
                'Короткое имя <после-преобразования-в-idn-тут-будет-больше-чем-64-символа@пример.com>'
113
            )->isValid()
114
        );
115
        $this->assertFalse(
116
            $validator->validate(
117
                'Короткое имя <тест@это-доменное-имя.после-преобразования-в-idn.будет-содержать-больше-254-символов.бла-бла-бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.com>'
118
            )->isValid()
119
        );
120
    }
121
122
    public function testValidateMx(): void
123
    {
124
        $this->markTestSkipped('Too slow :(');
125
126
        $validator = (new Email())
127
            ->checkDNS(true);
128
129
        $this->assertTrue($validator->validate('[email protected]')->isValid());
130
131
        $validator = $validator->checkDNS(false);
132
        $this->assertTrue($validator->validate('[email protected]')->isValid());
133
134
        $validator = $validator->checkDNS(true);
135
        $this->assertFalse($validator->validate('[email protected]')->isValid());
136
137
        $validator = $validator->checkDns(true);
138
        $validator = $validator->allowName(true);
139
        $emails = [
140
            '[email protected]',
141
            'Ivan Petrov <[email protected]>',
142
        ];
143
        foreach ($emails as $email) {
144
            $this->assertTrue(
145
                $validator->validate($email)->isValid(),
146
                "Email: '$email' failed to validate(checkDNS=true, allowName=true)"
147
            );
148
        }
149
    }
150
151
    public function malformedAddressesProvider(): array
152
    {
153
        return [
154
            // this is the demo email used in the proof of concept of the exploit
155
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com'],
156
            // trying more adresses
157
            ['"Attacker -Param2 -Param3"@test.com'],
158
            ['\'Attacker -Param2 -Param3\'@test.com'],
159
            ['"Attacker \" -Param2 -Param3"@test.com'],
160
            ["'Attacker \\' -Param2 -Param3'@test.com"],
161
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com'],
162
            // and even more variants
163
            ['"attacker\"\ -oQ/tmp/\ -X/var/www/cache/phpcode.php"@email.com'],
164
            ["\"attacker\\\"\0-oQ/tmp/\0-X/var/www/cache/phpcode.php\"@email.com"],
165
            ['"[email protected]\"-Xbeep"@email.com'],
166
167
            ["'attacker\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com"],
168
            ["'attacker\\\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com"],
169
            ["'attacker\\\\'\\ -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com"],
170
            ["'attacker\\';touch /tmp/hackme'@email.com"],
171
            ["'attacker\\\\';touch /tmp/hackme'@email.com"],
172
            ["'attacker\\';touch/tmp/hackme'@email.com"],
173
            ["'attacker\\\\';touch/tmp/hackme'@email.com"],
174
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com'],
175
        ];
176
    }
177
178
    /**
179
     * Test malicious email addresses that can be used to exploit SwiftMailer vulnerability CVE-2016-10074 while IDN is
180
     * disabled.
181
     * @see https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html
182
     * @dataProvider malformedAddressesProvider
183
     *
184
     * @param string $value
185
     */
186
    public function testMalformedAddressesIdnDisabled($value): void
187
    {
188
        $validator = (new Email())
189
            ->enableIDN(true);
190
        $this->assertFalse($validator->validate($value)->isValid());
191
    }
192
193
    /**
194
     * Test malicious email addresses that can be used to exploit SwiftMailer vulnerability CVE-2016-10074 while IDN is
195
     * enabled.
196
     * @see https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html
197
     * @dataProvider malformedAddressesProvider
198
     *
199
     * @param string $value
200
     */
201
    public function testMalformedAddressesIdnEnabled($value): void
202
    {
203
        if (!function_exists('idn_to_ascii')) {
204
            $this->markTestSkipped('Intl extension required');
205
206
            return;
207
        }
208
209
        $validator = (new Email())
210
            ->enableIDN(true);
211
        $this->assertFalse($validator->validate($value)->isValid());
212
    }
213
}
214