LoginRequest::throttleKey()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Devfaysal\LaravelAdmin\Http\Requests\Auth;
4
5
use Illuminate\Auth\Events\Lockout;
6
use Illuminate\Foundation\Http\FormRequest;
7
use Illuminate\Support\Facades\Auth;
8
use Illuminate\Support\Facades\RateLimiter;
9
use Illuminate\Support\Str;
10
use Illuminate\Validation\ValidationException;
11
12
class LoginRequest extends FormRequest
13
{
14
    /**
15
     * Determine if the user is authorized to make this request.
16
     *
17
     * @return bool
18
     */
19
    public function authorize()
20
    {
21
        return true;
22
    }
23
24
    /**
25
     * Get the validation rules that apply to the request.
26
     *
27
     * @return array
28
     */
29
    public function rules()
30
    {
31
        return [
32
            'email' => 'required|string|email',
33
            'password' => 'required|string',
34
        ];
35
    }
36
37
    /**
38
     * Attempt to authenticate the request's credentials.
39
     *
40
     * @return void
41
     *
42
     * @throws \Illuminate\Validation\ValidationException
43
     */
44
    public function authenticate()
45
    {
46
        $this->ensureIsNotRateLimited();
47
48
        if (! Auth::guard('admin')->attempt($this->only('email', 'password'), $this->filled('remember'))) {
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Illuminate\Contracts\Auth\Guard as the method attempt() does only exist in the following implementations of said interface: Illuminate\Auth\SessionGuard.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
49
            RateLimiter::hit($this->throttleKey());
50
51
            throw ValidationException::withMessages([
52
                'email' => __('auth.failed'),
53
            ]);
54
        }
55
56
        RateLimiter::clear($this->throttleKey());
57
    }
58
59
    /**
60
     * Ensure the login request is not rate limited.
61
     *
62
     * @return void
63
     *
64
     * @throws \Illuminate\Validation\ValidationException
65
     */
66
    public function ensureIsNotRateLimited()
67
    {
68
        if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
69
            return;
70
        }
71
72
        event(new Lockout($this));
73
74
        $seconds = RateLimiter::availableIn($this->throttleKey());
75
76
        throw ValidationException::withMessages([
77
            'email' => trans('auth.throttle', [
78
                'seconds' => $seconds,
79
                'minutes' => ceil($seconds / 60),
80
            ]),
81
        ]);
82
    }
83
84
    /**
85
     * Get the rate limiting throttle key for the request.
86
     *
87
     * @return string
88
     */
89
    public function throttleKey()
90
    {
91
        return Str::lower($this->input('email')).'|'.$this->ip();
92
    }
93
}
94