Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Validation\Rules;
4
 
5
use Illuminate\Container\Container;
6
use Illuminate\Contracts\Validation\DataAwareRule;
7
use Illuminate\Contracts\Validation\Rule;
8
use Illuminate\Contracts\Validation\UncompromisedVerifier;
9
use Illuminate\Contracts\Validation\ValidatorAwareRule;
10
use Illuminate\Support\Arr;
11
use Illuminate\Support\Facades\Validator;
12
use Illuminate\Support\Traits\Conditionable;
13
use InvalidArgumentException;
14
 
15
class Password implements Rule, DataAwareRule, ValidatorAwareRule
16
{
17
    use Conditionable;
18
 
19
    /**
20
     * The validator performing the validation.
21
     *
22
     * @var \Illuminate\Contracts\Validation\Validator
23
     */
24
    protected $validator;
25
 
26
    /**
27
     * The data under validation.
28
     *
29
     * @var array
30
     */
31
    protected $data;
32
 
33
    /**
34
     * The minimum size of the password.
35
     *
36
     * @var int
37
     */
38
    protected $min = 8;
39
 
40
    /**
41
     * If the password requires at least one uppercase and one lowercase letter.
42
     *
43
     * @var bool
44
     */
45
    protected $mixedCase = false;
46
 
47
    /**
48
     * If the password requires at least one letter.
49
     *
50
     * @var bool
51
     */
52
    protected $letters = false;
53
 
54
    /**
55
     * If the password requires at least one number.
56
     *
57
     * @var bool
58
     */
59
    protected $numbers = false;
60
 
61
    /**
62
     * If the password requires at least one symbol.
63
     *
64
     * @var bool
65
     */
66
    protected $symbols = false;
67
 
68
    /**
69
     * If the password should not have been compromised in data leaks.
70
     *
71
     * @var bool
72
     */
73
    protected $uncompromised = false;
74
 
75
    /**
76
     * The number of times a password can appear in data leaks before being considered compromised.
77
     *
78
     * @var int
79
     */
80
    protected $compromisedThreshold = 0;
81
 
82
    /**
83
     * Additional validation rules that should be merged into the default rules during validation.
84
     *
85
     * @var array
86
     */
87
    protected $customRules = [];
88
 
89
    /**
90
     * The failure messages, if any.
91
     *
92
     * @var array
93
     */
94
    protected $messages = [];
95
 
96
    /**
97
     * The callback that will generate the "default" version of the password rule.
98
     *
99
     * @var string|array|callable|null
100
     */
101
    public static $defaultCallback;
102
 
103
    /**
104
     * Create a new rule instance.
105
     *
106
     * @param  int  $min
107
     * @return void
108
     */
109
    public function __construct($min)
110
    {
111
        $this->min = max((int) $min, 1);
112
    }
113
 
114
    /**
115
     * Set the default callback to be used for determining a password's default rules.
116
     *
117
     * If no arguments are passed, the default password rule configuration will be returned.
118
     *
119
     * @param  static|callable|null  $callback
120
     * @return static|null
121
     */
122
    public static function defaults($callback = null)
123
    {
124
        if (is_null($callback)) {
125
            return static::default();
126
        }
127
 
128
        if (! is_callable($callback) && ! $callback instanceof static) {
129
            throw new InvalidArgumentException('The given callback should be callable or an instance of '.static::class);
130
        }
131
 
132
        static::$defaultCallback = $callback;
133
    }
134
 
135
    /**
136
     * Get the default configuration of the password rule.
137
     *
138
     * @return static
139
     */
140
    public static function default()
141
    {
142
        $password = is_callable(static::$defaultCallback)
143
                            ? call_user_func(static::$defaultCallback)
144
                            : static::$defaultCallback;
145
 
146
        return $password instanceof Rule ? $password : static::min(8);
147
    }
148
 
149
    /**
150
     * Get the default configuration of the password rule and mark the field as required.
151
     *
152
     * @return array
153
     */
154
    public static function required()
155
    {
156
        return ['required', static::default()];
157
    }
158
 
159
    /**
160
     * Get the default configuration of the password rule and mark the field as sometimes being required.
161
     *
162
     * @return array
163
     */
164
    public static function sometimes()
165
    {
166
        return ['sometimes', static::default()];
167
    }
168
 
169
    /**
170
     * Set the performing validator.
171
     *
172
     * @param  \Illuminate\Contracts\Validation\Validator  $validator
173
     * @return $this
174
     */
175
    public function setValidator($validator)
176
    {
177
        $this->validator = $validator;
178
 
179
        return $this;
180
    }
181
 
182
    /**
183
     * Set the data under validation.
184
     *
185
     * @param  array  $data
186
     * @return $this
187
     */
188
    public function setData($data)
189
    {
190
        $this->data = $data;
191
 
192
        return $this;
193
    }
194
 
195
    /**
196
     * Sets the minimum size of the password.
197
     *
198
     * @param  int  $size
199
     * @return $this
200
     */
201
    public static function min($size)
202
    {
203
        return new static($size);
204
    }
205
 
206
    /**
207
     * Ensures the password has not been compromised in data leaks.
208
     *
209
     * @param  int  $threshold
210
     * @return $this
211
     */
212
    public function uncompromised($threshold = 0)
213
    {
214
        $this->uncompromised = true;
215
 
216
        $this->compromisedThreshold = $threshold;
217
 
218
        return $this;
219
    }
220
 
221
    /**
222
     * Makes the password require at least one uppercase and one lowercase letter.
223
     *
224
     * @return $this
225
     */
226
    public function mixedCase()
227
    {
228
        $this->mixedCase = true;
229
 
230
        return $this;
231
    }
232
 
233
    /**
234
     * Makes the password require at least one letter.
235
     *
236
     * @return $this
237
     */
238
    public function letters()
239
    {
240
        $this->letters = true;
241
 
242
        return $this;
243
    }
244
 
245
    /**
246
     * Makes the password require at least one number.
247
     *
248
     * @return $this
249
     */
250
    public function numbers()
251
    {
252
        $this->numbers = true;
253
 
254
        return $this;
255
    }
256
 
257
    /**
258
     * Makes the password require at least one symbol.
259
     *
260
     * @return $this
261
     */
262
    public function symbols()
263
    {
264
        $this->symbols = true;
265
 
266
        return $this;
267
    }
268
 
269
    /**
270
     * Specify additional validation rules that should be merged with the default rules during validation.
271
     *
272
     * @param  string|array  $rules
273
     * @return $this
274
     */
275
    public function rules($rules)
276
    {
277
        $this->customRules = Arr::wrap($rules);
278
 
279
        return $this;
280
    }
281
 
282
    /**
283
     * Determine if the validation rule passes.
284
     *
285
     * @param  string  $attribute
286
     * @param  mixed  $value
287
     * @return bool
288
     */
289
    public function passes($attribute, $value)
290
    {
291
        $this->messages = [];
292
 
293
        $validator = Validator::make(
294
            $this->data,
295
            [$attribute => array_merge(['string', 'min:'.$this->min], $this->customRules)],
296
            $this->validator->customMessages,
297
            $this->validator->customAttributes
298
        )->after(function ($validator) use ($attribute, $value) {
299
            if (! is_string($value)) {
300
                return;
301
            }
302
 
303
            if ($this->mixedCase && ! preg_match('/(\p{Ll}+.*\p{Lu})|(\p{Lu}+.*\p{Ll})/u', $value)) {
304
                $validator->errors()->add(
305
                    $attribute,
306
                    $this->getErrorMessage('validation.password.mixed')
307
                );
308
            }
309
 
310
            if ($this->letters && ! preg_match('/\pL/u', $value)) {
311
                $validator->errors()->add(
312
                    $attribute,
313
                    $this->getErrorMessage('validation.password.letters')
314
                );
315
            }
316
 
317
            if ($this->symbols && ! preg_match('/\p{Z}|\p{S}|\p{P}/u', $value)) {
318
                $validator->errors()->add(
319
                    $attribute,
320
                    $this->getErrorMessage('validation.password.symbols')
321
                );
322
            }
323
 
324
            if ($this->numbers && ! preg_match('/\pN/u', $value)) {
325
                $validator->errors()->add(
326
                    $attribute,
327
                    $this->getErrorMessage('validation.password.numbers')
328
                );
329
            }
330
        });
331
 
332
        if ($validator->fails()) {
333
            return $this->fail($validator->messages()->all());
334
        }
335
 
336
        if ($this->uncompromised && ! Container::getInstance()->make(UncompromisedVerifier::class)->verify([
337
            'value' => $value,
338
            'threshold' => $this->compromisedThreshold,
339
        ])) {
340
            return $this->fail($this->getErrorMessage('validation.password.uncompromised'));
341
        }
342
 
343
        return true;
344
    }
345
 
346
    /**
347
     * Get the validation error message.
348
     *
349
     * @return array
350
     */
351
    public function message()
352
    {
353
        return $this->messages;
354
    }
355
 
356
    /**
357
     * Get the translated password error message.
358
     *
359
     * @param  string  $key
360
     * @return string
361
     */
362
    protected function getErrorMessage($key)
363
    {
364
        if (($message = $this->validator->getTranslator()->get($key)) !== $key) {
365
            return $message;
366
        }
367
 
368
        $messages = [
369
            'validation.password.mixed' => 'The :attribute must contain at least one uppercase and one lowercase letter.',
370
            'validation.password.letters' => 'The :attribute must contain at least one letter.',
371
            'validation.password.symbols' => 'The :attribute must contain at least one symbol.',
372
            'validation.password.numbers' => 'The :attribute must contain at least one number.',
373
            'validation.password.uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
374
        ];
375
 
376
        return $messages[$key];
377
    }
378
 
379
    /**
380
     * Adds the given failures, and return false.
381
     *
382
     * @param  array|string  $messages
383
     * @return bool
384
     */
385
    protected function fail($messages)
386
    {
387
        $messages = collect(Arr::wrap($messages))->map(function ($message) {
388
            return $this->validator->getTranslator()->get($message);
389
        })->all();
390
 
391
        $this->messages = array_merge($this->messages, $messages);
392
 
393
        return false;
394
    }
395
}