Passed
Pull Request — master (#416)
by Alexander
05:10 queued 02:36
created

EmailTest::beforeTestValidationFailed()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
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
use Yiisoft\Validator\Rule\EmailHandler;
10
use Yiisoft\Validator\Tests\Rule\Base\DifferentRuleInHandlerTestTrait;
11
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
12
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
13
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
14
15
final class EmailTest extends TestCase
16
{
17
    use DifferentRuleInHandlerTestTrait;
18
    use RuleWithOptionsTestTrait;
19
    use SkipOnErrorTestTrait;
20
    use WhenTestTrait;
21
22
    public function testGetName(): void
23
    {
24
        $rule = new Email();
25
        $this->assertSame('email', $rule->getName());
26
    }
27
28
    public function testSkipOnError(): void
29
    {
30
        $this->testSkipOnErrorInternal(new Email(), new Email(skipOnError: true));
31
    }
32
33
    public function testWhen(): void
34
    {
35
        $when = static fn (mixed $value): bool => $value !== null;
36
        $this->testWhenInternal(new Email(), new Email(when: $when));
37
    }
38
39
    public function dataOptions(): array
40
    {
41
        return [
42
            [
43
                new Email(),
44
                [
45
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
46
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
47
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
48
                    'allowName' => false,
49
                    'checkDNS' => false,
50
                    'enableIDN' => false,
51
                    'incorrectInputMessage' => [
52
                        'template' => 'The value must have a string type.',
53
                        'parameters' => [],
54
                    ],
55
                    'message' => [
56
                        'template' => 'This value is not a valid email address.',
57
                        'parameters' => [],
58
                    ],
59
                    'skipOnEmpty' => false,
60
                    'skipOnError' => false,
61
                ],
62
            ],
63
            [
64
                new Email(allowName: true),
65
                [
66
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
67
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
68
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
69
                    'allowName' => true,
70
                    'checkDNS' => false,
71
                    'enableIDN' => false,
72
                    'incorrectInputMessage' => [
73
                        'template' => 'The value must have a string type.',
74
                        'parameters' => [],
75
                    ],
76
                    'message' => [
77
                        'template' => 'This value is not a valid email address.',
78
                        'parameters' => [],
79
                    ],
80
                    'skipOnEmpty' => false,
81
                    'skipOnError' => false,
82
                ],
83
            ],
84
            [
85
                new Email(allowName: true, checkDNS: true),
86
                [
87
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
88
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
89
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
90
                    'allowName' => true,
91
                    'checkDNS' => true,
92
                    'enableIDN' => false,
93
                    'incorrectInputMessage' => [
94
                        'template' => 'The value must have a string type.',
95
                        'parameters' => [],
96
                    ],
97
                    'message' => [
98
                        'template' => 'This value is not a valid email address.',
99
                        'parameters' => [],
100
                    ],
101
                    'skipOnEmpty' => false,
102
                    'skipOnError' => false,
103
                ],
104
            ],
105
            [
106
                new Email(allowName: true, enableIDN: true),
107
                [
108
                    'pattern' => '/^[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/',
109
                    'fullPattern' => '/^[^@]*<[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&\'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?>$/',
110
                    'idnEmailPattern' => '/^([a-zA-Z0-9._%+-]+)@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.)|(([\w-]+\.)+))([a-zA-Z]{2,4}|\d{1,3})(\]?)$/',
111
                    'allowName' => true,
112
                    'checkDNS' => false,
113
                    'enableIDN' => true,
114
                    'incorrectInputMessage' => [
115
                        'template' => 'The value must have a string type.',
116
                        'parameters' => [],
117
                    ],
118
                    'message' => [
119
                        'template' => 'This value is not a valid email address.',
120
                        'parameters' => [],
121
                    ],
122
                    'skipOnEmpty' => false,
123
                    'skipOnError' => false,
124
                ],
125
            ],
126
        ];
127
    }
128
129
    public function dataValidationPassed(): array
130
    {
131
        $rule = new Email();
132
        $ruleAllowedName = new Email(allowName: true);
133
        $ruleEnabledIDN = new Email(enableIDN: true);
134
        $ruleEnabledIDNandAllowedName = new Email(allowName: true, enableIDN: true);
135
136
        return [
137
            ['[email protected]', [$rule]],
138
            ['[email protected]', [$rule]],
139
            ['[email protected]', [$rule]],
140
            ['[email protected]', [$rule]],
141
            ['user+mailbox/[email protected]', [$rule]],
142
            ['!#$%&\'*+-/=?^_`.{|}[email protected]', [$rule]],
143
            ['[email protected]', [$rule]], // checkDNS is disabled
144
            ['[email protected]', [$rule]],
145
            [str_repeat('a', 64) . '@gmail.com', [$rule]],
146
            ['name@' . str_repeat('a', 245) . '.com', [$rule]],
147
            ['[email protected]', [$rule]],
148
149
            ['[email protected]', [$ruleAllowedName]],
150
            ['[email protected]', [$ruleAllowedName]],
151
            ['[email protected]', [$ruleAllowedName]],
152
            ['Carsten Brandt <[email protected]>', [$ruleAllowedName]],
153
            ['"Carsten Brandt" <[email protected]>', [$ruleAllowedName]],
154
            ['<[email protected]>', [$ruleAllowedName]],
155
            ['[email protected]', [$ruleAllowedName]],
156
            ['John Smith <[email protected]>', [$ruleAllowedName]],
157
            [
158
                '"This name is longer than 64 characters. Blah blah blah blah blah" <[email protected]>',
159
                [$ruleAllowedName],
160
            ],
161
162
            ['[email protected]', [$ruleEnabledIDN]],
163
            ['[email protected]', [$ruleEnabledIDN]],
164
            ['example@äüößìà.de', [$ruleEnabledIDN]],
165
            ['[email protected]', [$ruleEnabledIDN]],
166
            ['info@örtliches.de', [$ruleEnabledIDN]],
167
            ['sam@рмкреатиф.ru', [$ruleEnabledIDN]],
168
            ['[email protected]', [$ruleEnabledIDN]],
169
            ['[email protected]', [$ruleEnabledIDN]],
170
            ['üñîçøðé@üñîçøðé.com', [$ruleEnabledIDN]],
171
172
            ['info@örtliches.de', [$ruleEnabledIDNandAllowedName]],
173
            ['Information <info@örtliches.de>', [$ruleEnabledIDNandAllowedName]],
174
            ['sam@рмкреатиф.ru', [$ruleEnabledIDNandAllowedName]],
175
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
176
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
177
            ['Carsten Brandt <[email protected]>', [$ruleEnabledIDNandAllowedName]],
178
            ['"Carsten Brandt" <[email protected]>', [$ruleEnabledIDNandAllowedName]],
179
            ['üñîçøðé 日本国 <üñîçøðé@üñîçøðé.com>', [$ruleEnabledIDNandAllowedName]],
180
            ['<[email protected]>', [$ruleEnabledIDNandAllowedName]],
181
            ['[email protected]', [$ruleEnabledIDNandAllowedName]],
182
            ['John Smith <[email protected]>', [$ruleEnabledIDNandAllowedName]],
183
            [
184
                '"Такое имя достаточно длинное, но оно все равно может пройти валидацию" <[email protected]>',
185
                [$ruleEnabledIDNandAllowedName],
186
            ],
187
188
            ['[email protected]', [new Email(checkDNS: true)]],
189
190
            ['[email protected]', [new Email(allowName: true, checkDNS: true)]],
191
            ['Ivan Petrov <[email protected]>', [new Email(allowName: true, checkDNS: true)]],
192
            ['name@ñandu.cl', [new Email(checkDNS: true, enableIDN: true)]],
193
        ];
194
    }
195
196
    public function dataValidationFailed(): array
197
    {
198
        $rule = new Email();
199
        $ruleAllowedName = new Email(allowName: true);
200
        $ruleEnabledIDN = new Email(enableIDN: true);
201
        $ruleEnabledIDNandAllowedName = new Email(allowName: true, enableIDN: true);
202
        $errors = ['' => ['This value is not a valid email address.']];
203
        $incorrectInputErrors = ['' => ['The value must have a string type.']];
204
205
        return [
206
            'incorrect input, integer' => [1, [$rule], $incorrectInputErrors],
207
            'incorrect input, array containing string element' => [
208
                ['[email protected]'],
209
                [$ruleAllowedName],
210
                $incorrectInputErrors,
211
            ],
212
            'custom incorrect input message' => [
213
                1,
214
                [new Email(incorrectInputMessage: 'Custom incorrect input message.')],
215
                ['' => ['Custom incorrect input message.']],
216
            ],
217
            'custom incorrect input message with parameters' => [
218
                1,
219
                [new Email(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')],
220
                ['' => ['Attribute - , type - int.']],
221
            ],
222
            'custom incorrect input message with parameters, attribute set' => [
223
                ['data' => 1],
224
                ['data' => [new Email(incorrectInputMessage: 'Attribute - {attribute}, type - {type}.')]],
225
                ['data' => ['Attribute - data, type - int.']],
226
            ],
227
228
            ['rmcreative.ru', [$rule], $errors],
229
            ['Carsten Brandt <[email protected]>', [$rule], $errors],
230
            ['"Carsten Brandt" <[email protected]>', [$rule], $errors],
231
            ['<[email protected]>', [$rule], $errors],
232
            ['info@örtliches.de', [$rule], $errors],
233
            ['sam@рмкреатиф.ru', [$rule], $errors],
234
            ['[email protected]', [$rule], $errors],
235
            [str_repeat('a', 65) . '@gmail.com', [$rule], $errors],
236
            ['name@' . str_repeat('a', 246) . '.com', [$rule], $errors],
237
238
            // Malicious email addresses that can be used to exploit SwiftMailer vulnerability CVE-2016-10074 while IDN
239
            // is disabled.
240
            // https://legalhackers.com/advisories/SwiftMailer-Exploit-Remote-Code-Exec-CVE-2016-10074-Vuln.html
241
242
            // This is the demo email used in the proof of concept of the exploit
243
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
244
245
            // Trying more addresses
246
            ['"Attacker -Param2 -Param3"@test.com', [$rule], $errors],
247
            ['\'Attacker -Param2 -Param3\'@test.com', [$rule], $errors],
248
            ['"Attacker \" -Param2 -Param3"@test.com', [$rule], $errors],
249
            ["'Attacker \\' -Param2 -Param3'@test.com", [$rule], $errors],
250
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
251
252
            // And even more variants
253
            ['"attacker\"\ -oQ/tmp/\ -X/var/www/cache/phpcode.php"@email.com', [$rule], $errors],
254
            ["\"attacker\\\"\0-oQ/tmp/\0-X/var/www/cache/phpcode.php\"@email.com", [$rule], $errors],
255
            ['"[email protected]\"-Xbeep"@email.com', [$rule], $errors],
256
            ["'attacker\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
257
            ["'attacker\\\\' -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
258
            ["'attacker\\\\'\\ -oQ/tmp/ -X/var/www/cache/phpcode.php'@email.com", [$rule], $errors],
259
            ["'attacker\\';touch /tmp/hackme'@email.com", [$rule], $errors],
260
            ["'attacker\\\\';touch /tmp/hackme'@email.com", [$rule], $errors],
261
            ["'attacker\\';touch/tmp/hackme'@email.com", [$rule], $errors],
262
            ["'attacker\\\\';touch/tmp/hackme'@email.com", [$rule], $errors],
263
            ['"attacker\" -oQ/tmp/ -X/var/www/cache/phpcode.php "@email.com', [$rule], $errors],
264
265
            ['rmcreative.ru', [$ruleAllowedName], $errors],
266
            ['info@örtliches.de', [$ruleAllowedName], $errors],
267
            ['üñîçøðé@üñîçøðé.com', [$ruleAllowedName], $errors],
268
            ['sam@рмкреатиф.ru', [$ruleAllowedName], $errors],
269
            ['Informtation [email protected]', [$ruleAllowedName], $errors],
270
            ['John Smith <example.com>', [$ruleAllowedName], $errors],
271
            [
272
                'Short Name <localPartMoreThan64Characters-blah-blah-blah-blah-blah-blah-blah-blah@example.com>',
273
                [$ruleAllowedName],
274
                $errors,
275
            ],
276
            [
277
                'Short Name <domainNameIsMoreThan254Characters@example-blah-blah-blah-blah-blah-blah-blah-blah-blah-' .
278
                'blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-' .
279
                'blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah' .
280
                '.com>',
281
                [$ruleAllowedName],
282
                $errors,
283
            ],
284
285
            ['rmcreative.ru', [$ruleEnabledIDN], $errors],
286
            ['Carsten Brandt <[email protected]>', [$ruleEnabledIDN], $errors],
287
            ['"Carsten Brandt" <[email protected]>', [$ruleEnabledIDN], $errors],
288
            ['<[email protected]>', [$ruleEnabledIDN], $errors],
289
290
            [
291
                'Короткое имя <тест@это-доменное-имя.после-преобразования-в-idn.будет-содержать-больше-254-символов.' .
292
                'бла-бла-бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-бла.бла-бла-бла-бла-бла-' .
293
                'бла.com>',
294
                [$ruleEnabledIDNandAllowedName],
295
                $errors,
296
            ],
297
            ['Information info@örtliches.de', [$ruleEnabledIDNandAllowedName], $errors],
298
            ['rmcreative.ru', [$ruleEnabledIDNandAllowedName], $errors],
299
            ['John Smith <example.com>', [$ruleEnabledIDNandAllowedName], $errors],
300
            [
301
                'Короткое имя <после-преобразования-в-idn-тут-будет-больше-чем-64-символа@пример.com>',
302
                [$ruleEnabledIDNandAllowedName],
303
                $errors,
304
            ],
305
306
            ['name@ñandu.cl', [new Email(checkDNS: true)], $errors],
307
            ['gmail.con', [new Email(checkDNS: true)], $errors],
308
            [
309
                '[email protected]',
310
                [new Email(checkDNS: true)],
311
                $errors,
312
            ],
313
314
            'custom message' => [
315
                '[email protected]',
316
                [new Email(checkDNS: true, message: 'Custom message.')],
317
                ['' => ['Custom message.']],
318
            ],
319
            'custom message with parameters' => [
320
                '[email protected]',
321
                [new Email(checkDNS: true, message: 'Attribute - {attribute}, value - {value}.')],
322
                ['' => ['Attribute - , value - [email protected].']],
323
            ],
324
            'custom message with parameters, attribute set' => [
325
                ['data' => '[email protected]'],
326
                ['data' => new Email(checkDNS: true, message: 'Attribute - {attribute}, value - {value}.')],
327
                ['data' => ['Attribute - data, value - [email protected].']],
328
            ],
329
        ];
330
    }
331
332
    protected function getDifferentRuleInHandlerItems(): array
333
    {
334
        return [Email::class, EmailHandler::class];
335
    }
336
}
337