Issues (138)

tests/Rule/EmailTest.php (1 issue)

Labels
Severity
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Validator\Tests\Rule;
6
7
use InvalidArgumentException;
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\RuleTestCase;
12
use Yiisoft\Validator\Tests\Rule\Base\RuleWithOptionsTestTrait;
13
use Yiisoft\Validator\Tests\Rule\Base\SkipOnErrorTestTrait;
14
use Yiisoft\Validator\Tests\Rule\Base\WhenTestTrait;
15
16
final class EmailTest extends RuleTestCase
17
{
18
    use DifferentRuleInHandlerTestTrait;
19
    use RuleWithOptionsTestTrait;
20
    use SkipOnErrorTestTrait;
21
    use WhenTestTrait;
22
23
    public function dataInvalidConfiguration(): array
24
    {
25
        return [
26
            [['pattern' => ''], 'Pattern can\'t be empty.'],
27
            [['fullPattern' => ''], 'Full pattern can\'t be empty.'],
28
            [['idnEmailPattern' => ''], 'IDN e-mail pattern can\'t be empty.'],
29
        ];
30
    }
31
32
    /**
33
     * @dataProvider dataInvalidConfiguration
34
     */
35
    public function testinvalidConfiguration(array $arguments, string $expectedExceptionMessage): void
36
    {
37
        $this->expectException(InvalidArgumentException::class);
38
        $this->expectExceptionMessage($expectedExceptionMessage);
39
        new Email(...$arguments);
0 ignored issues
show
$arguments is expanded, but the parameter $pattern of Yiisoft\Validator\Rule\Email::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

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