Completed
Push — master ( cc63b0...03b333 )
by Abdelrahman
02:27
created

SessionGuard::getUserBySession()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
cc 2
eloc 2
nc 2
nop 0
rs 10
1
<?php
2
3
/*
4
 * NOTICE OF LICENSE
5
 *
6
 * Part of the Rinvex Fort Package.
7
 *
8
 * This source file is subject to The MIT License (MIT)
9
 * that is bundled with this package in the LICENSE file.
10
 *
11
 * Package: Rinvex Fort Package
12
 * License: The MIT License (MIT)
13
 * Link:    https://rinvex.com
14
 */
15
16
namespace Rinvex\Fort\Guards;
17
18
use Carbon\Carbon;
19
use RuntimeException;
20
use Illuminate\Support\Str;
21
use Illuminate\Http\Request;
22
use Illuminate\Http\Response;
23
use Illuminate\Auth\GuardHelpers;
24
use Rinvex\Fort\Traits\ThrottlesLogins;
25
use Illuminate\Session\SessionInterface;
26
use Illuminate\Contracts\Events\Dispatcher;
27
use Rinvex\Fort\Services\TwoFactorTotpProvider;
28
use Rinvex\Fort\Services\TwoFactorAuthyProvider;
29
use Rinvex\Fort\Contracts\StatefulGuardContract;
30
use Illuminate\Contracts\Auth\SupportsBasicAuth;
31
use Rinvex\Fort\Contracts\UserRepositoryContract;
32
use Rinvex\Fort\Contracts\AuthenticatableContract;
33
use Rinvex\Fort\Exceptions\InvalidPersistenceException;
34
use Illuminate\Contracts\Cookie\QueueingFactory as CookieJar;
35
36
class SessionGuard implements StatefulGuardContract, SupportsBasicAuth
37
{
38
    use GuardHelpers, ThrottlesLogins;
39
40
    /**
41
     * Constant representing a successful login.
42
     *
43
     * @var string
44
     */
45
    const AUTH_VALID = 'rinvex.fort::message.auth.valid';
46
47
    /**
48
     * Constant representing a successful login.
49
     *
50
     * @var string
51
     */
52
    const AUTH_LOGIN = 'rinvex.fort::message.auth.login';
53
54
    /**
55
     * Constant representing a failed login.
56
     *
57
     * @var string
58
     */
59
    const AUTH_FAILED = 'rinvex.fort::message.auth.failed';
60
61
    /**
62
     * Constant representing an unverified user.
63
     *
64
     * @var string
65
     */
66
    const AUTH_UNVERIFIED = 'rinvex.fort::message.auth.unverified';
67
68
    /**
69
     * Constant representing a moderated user.
70
     *
71
     * @var string
72
     */
73
    const AUTH_MODERATED = 'rinvex.fort::message.auth.moderated';
74
75
    /**
76
     * Constant representing a locked out user.
77
     *
78
     * @var string
79
     */
80
    const AUTH_LOCKED_OUT = 'rinvex.fort::message.auth.lockout';
81
82
    /**
83
     * Constant representing a user with Two-Factor authentication enabled.
84
     *
85
     * @var string
86
     */
87
    const AUTH_TWOFACTOR_REQUIRED = 'rinvex.fort::message.verification.twofactor.totp.required';
88
89
    /**
90
     * Constant representing a user with Two-Factor failed authentication.
91
     *
92
     * @var string
93
     */
94
    const AUTH_TWOFACTOR_FAILED = 'rinvex.fort::message.verification.twofactor.invalid_token';
95
96
    /**
97
     * Constant representing a user with phone verified.
98
     *
99
     * @var string
100
     */
101
    const AUTH_PHONE_VERIFIED = 'rinvex.fort::message.verification.phone.verified';
102
103
    /**
104
     * Constant representing a user with phone verified.
105
     *
106
     * @var string
107
     */
108
    const AUTH_REGISTERED = 'rinvex.fort::message.register.success';
109
110
    /**
111
     * Constant representing a logged out user.
112
     *
113
     * @var string
114
     */
115
    const AUTH_LOGOUT = 'rinvex.fort::message.auth.logout';
116
117
    /**
118
     * The name of the Guard. Typically "session".
119
     *
120
     * Corresponds to driver name in authentication configuration.
121
     *
122
     * @var string
123
     */
124
    protected $name;
125
126
    /**
127
     * The user we last attempted to retrieve.
128
     *
129
     * @var \Rinvex\Fort\Contracts\AuthenticatableContract
130
     */
131
    protected $lastAttempted;
132
133
    /**
134
     * Indicates if the user was authenticated via a recaller cookie.
135
     *
136
     * @var bool
137
     */
138
    protected $viaRemember = false;
139
140
    /**
141
     * The session used by the guard.
142
     *
143
     * @var \Illuminate\Session\SessionInterface
144
     */
145
    protected $session;
146
147
    /**
148
     * The Illuminate cookie creator service.
149
     *
150
     * @var \Illuminate\Contracts\Cookie\QueueingFactory
151
     */
152
    protected $cookie;
153
154
    /**
155
     * The request instance.
156
     *
157
     * @var \Illuminate\Http\Request
158
     */
159
    protected $request;
160
161
    /**
162
     * The event dispatcher instance.
163
     *
164
     * @var \Illuminate\Contracts\Events\Dispatcher
165
     */
166
    protected $events;
167
168
    /**
169
     * Indicates if the logout method has been called.
170
     *
171
     * @var bool
172
     */
173
    protected $loggedOut = false;
174
175
    /**
176
     * Indicates if there's logout attempt.
177
     *
178
     * @var bool
179
     */
180
    protected $logoutAttempted = false;
181
182
    /**
183
     * Indicates if a token user retrieval has been attempted.
184
     *
185
     * @var bool
186
     */
187
    protected $tokenRetrievalAttempted = false;
0 ignored issues
show
Comprehensibility Naming introduced by
The variable name $tokenRetrievalAttempted exceeds the maximum configured length of 20.

Very long variable names usually make code harder to read. It is therefore recommended not to make variable names too verbose.

Loading history...
188
189
    /**
190
     * Create a new authentication guard.
191
     *
192
     * @param string                                        $name
193
     * @param \Rinvex\Fort\Contracts\UserRepositoryContract $provider
194
     * @param \Illuminate\Session\SessionInterface          $session
195
     * @param \Illuminate\Http\Request                      $request
0 ignored issues
show
Documentation introduced by
Should the type for parameter $request not be null|Request?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
196
     *
197
     * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
198
     */
199
    public function __construct($name, UserRepositoryContract $provider, SessionInterface $session, Request $request = null)
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 124 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
200
    {
201
        $this->name     = $name;
202
        $this->session  = $session;
203
        $this->request  = $request;
204
        $this->provider = $provider;
0 ignored issues
show
Documentation Bug introduced by
It seems like $provider of type object<Rinvex\Fort\Contr...UserRepositoryContract> is incompatible with the declared type object<Illuminate\Contracts\Auth\UserProvider> of property $provider.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
205
    }
206
207
    /**
208
     * Return login attempt user.
209
     *
210
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|object|null
211
     */
212
    public function attemptUser()
213
    {
214
        if (! empty($session = session('rinvex.fort.twofactor.persistence')) && $persistence = $this->getPersistenceByToken($session)) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 136 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
215
            return $this->provider->find($persistence->user_id);
0 ignored issues
show
Bug introduced by
The method find() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The property user_id does not seem to exist in Rinvex\Fort\Repositories\PersistenceRepository.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
216
        }
217
    }
218
219
    /**
220
     * Get the currently authenticated user.
221
     *
222
     * @return null|\Rinvex\Fort\Contracts\AuthenticatableContract
0 ignored issues
show
Documentation introduced by
Should the return type not be null|\Illuminate\Contracts\Auth\Authenticatable?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
223
     *
224
     * @throws \Rinvex\Fort\Exceptions\InvalidPersistenceException
225
     */
226
    public function user()
227
    {
228
        if ($this->loggedOut) {
229
            return;
230
        }
231
232
        // If we've already retrieved the user for the current request we can just
233
        // return it back immediately. We do not want to fetch the user data on
234
        // every call to this method because that would be tremendously slow.
235
        if (! is_null($this->user)) {
236
            return $this->user;
237
        }
238
239
        $userBySession = $this->getUserBySession();
240
        $userByCookie  = $this->getUserByCookie();
241
242
        if (! $this->logoutAttempted && ($userBySession || $userByCookie) && ! $this->getPersistenceByToken($this->session->getId())) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
243
            $this->logout();
244
245
            // Fire the automatic logout event
246
            $this->events->fire('rinvex.fort.auth.autologout');
247
248
            // Throw invalid persistence exception
249
            throw new InvalidPersistenceException();
250
        }
251
252
        // First we will try to load the user using the identifier in the session if
253
        // one exists. Otherwise we will check for a "remember me" cookie in this
254
        // request, and if one exists, attempt to retrieve the user using that.
255
        if ($userBySession) {
256
            // Fire the authenticated event
257
            $this->events->fire('rinvex.fort.auth.user', [$userBySession]);
258
        }
259
260
        // If the user is null, but we decrypt a "recaller" cookie we can attempt to
261
        // pull the user data on that cookie which serves as a remember cookie on
262
        // the application. Once we have a user we can return it to the caller.
263
        if (is_null($userBySession) && $userByCookie) {
264
            $this->updateSession($userByCookie->getAuthIdentifier());
265
266
            // Fire the authentication login event
267
            $this->events->fire('rinvex.fort.auth.login', [$userByCookie, true]);
268
        }
269
270
        $user = $userBySession ?: $userByCookie;
271
272
        // Update last activity
273
        if (! $this->logoutAttempted && ! is_null($user)) {
274
            $this->provider->update($user->id, ['active_at' => new Carbon()]);
0 ignored issues
show
Bug introduced by
The method update() does not exist on Illuminate\Contracts\Auth\UserProvider. Did you maybe mean updateRememberToken()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
275
        }
276
277
        return $this->user = $user;
278
    }
279
280
    /**
281
     * Get the ID for the currently authenticated user.
282
     *
283
     * @return int|null
284
     */
285
    public function id()
0 ignored issues
show
Coding Style introduced by
This method's name is shorter than the configured minimum length of 3 characters.

Even though PHP does not care about the name of your methods, it is generally a good practice to choose method names which can be easily understood by other human readers.

Loading history...
286
    {
287
        if ($this->loggedOut) {
288
            return;
289
        }
290
291
        $id = $this->session->get($this->getName());
292
293
        if (is_null($id) && $this->user()) {
294
            $id = $this->user()->getAuthIdentifier();
295
        }
296
297
        return $id;
298
    }
299
300
    /**
301
     * Pull a user from the repository by its recaller ID.
302
     *
303
     * @param string $recaller
304
     *
305
     * @return mixed
306
     */
307
    protected function getUserByRecaller($recaller)
308
    {
309
        if ($this->validRecaller($recaller) && ! $this->tokenRetrievalAttempted) {
310
            $this->tokenRetrievalAttempted = true;
311
312
            list($id, $token) = explode('|', $recaller, 2);
313
314
            $this->viaRemember = ! is_null($user = $this->provider->findByToken($id, $token));
0 ignored issues
show
Bug introduced by
The method findByToken() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
315
316
            return $user;
317
        }
318
    }
319
320
    /**
321
     * Get the decrypted recaller cookie for the request.
322
     *
323
     * @return string|null
324
     */
325
    protected function getRecaller()
326
    {
327
        return $this->request->cookies->get($this->getRecallerName());
328
    }
329
330
    /**
331
     * Get the user ID from the recaller cookie.
332
     *
333
     * @return string|null
334
     */
335
    protected function getRecallerId()
336
    {
337
        if ($this->validRecaller($recaller = $this->getRecaller())) {
338
            return head(explode('|', $recaller));
339
        }
340
    }
341
342
    /**
343
     * Determine if the recaller cookie is in a valid format.
344
     *
345
     * @param mixed $recaller
346
     *
347
     * @return bool
348
     */
349
    protected function validRecaller($recaller)
350
    {
351
        if (! is_string($recaller) || ! Str::contains($recaller, '|')) {
352
            return false;
353
        }
354
355
        $segments = explode('|', $recaller);
356
357
        return count($segments) == 2 && trim($segments[0]) !== '' && trim($segments[1]) !== '';
358
    }
359
360
    /**
361
     * Log a user into the application without sessions or cookies.
362
     *
363
     * @param array $credentials
364
     *
365
     * @return bool
366
     */
367
    public function once(array $credentials = [])
368
    {
369
        if ($this->validate($credentials)) {
370
            $this->setUser($this->lastAttempted);
371
372
            return true;
373
        }
374
375
        return false;
376
    }
377
378
    /**
379
     * Validate a user's credentials.
380
     *
381
     * @param array $credentials
382
     *
383
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
384
     */
385
    public function validate(array $credentials = [])
386
    {
387
        return $this->attempt($credentials, false, false);
388
    }
389
390
    /**
391
     * Attempt to authenticate using HTTP Basic Auth.
392
     *
393
     * @param string $field
394
     * @param array  $extraConditions
395
     *
396
     * @return \Illuminate\Http\Response|null
397
     */
398
    public function basic($field = 'email', $extraConditions = [])
399
    {
400
        if ($this->check()) {
401
            return;
402
        }
403
404
        // If a username is set on the HTTP basic request, we will return out without
405
        // interrupting the request lifecycle. Otherwise, we'll need to generate a
406
        // request indicating that the given credentials were invalid for login.
407
        if ($this->attemptBasic($this->getRequest(), $field, $extraConditions)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->attemptBasic($thi...ield, $extraConditions) of type false|string is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
408
            return;
409
        }
410
411
        return $this->getBasicResponse();
412
    }
413
414
    /**
415
     * Perform a stateless HTTP Basic login attempt.
416
     *
417
     * @param string $field
418
     * @param array  $extraConditions
419
     *
420
     * @return \Illuminate\Http\Response|null
421
     */
422
    public function onceBasic($field = 'email', $extraConditions = [])
423
    {
424
        $credentials = $this->getBasicCredentials($this->getRequest(), $field);
425
426
        if (! $this->once(array_merge($credentials, $extraConditions))) {
427
            return $this->getBasicResponse();
428
        }
429
    }
430
431
    /**
432
     * Attempt to authenticate using basic authentication.
433
     *
434
     * @param \Illuminate\Http\Request $request
435
     * @param string                   $field
436
     * @param array                    $extraConditions
437
     *
438
     * @return bool
0 ignored issues
show
Documentation introduced by
Should the return type not be false|string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
439
     */
440
    protected function attemptBasic(Request $request, $field, $extraConditions = [])
441
    {
442
        if (! $request->getUser()) {
443
            return false;
444
        }
445
446
        $credentials = $this->getBasicCredentials($request, $field);
447
448
        return $this->attempt(array_merge($credentials, $extraConditions));
449
    }
450
451
    /**
452
     * Get the credential array for a HTTP Basic request.
453
     *
454
     * @param \Illuminate\Http\Request $request
455
     * @param string                   $field
456
     *
457
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use array<string,string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
458
     */
459
    protected function getBasicCredentials(Request $request, $field)
460
    {
461
        return [
462
            $field     => $request->getUser(),
463
            'password' => $request->getPassword(),
464
        ];
465
    }
466
467
    /**
468
     * Get the response for basic authentication.
469
     *
470
     * @return \Illuminate\Http\Response
471
     */
472
    protected function getBasicResponse()
473
    {
474
        $headers = ['WWW-Authenticate' => 'Basic'];
475
476
        return new Response('Invalid credentials.', 401, $headers);
477
    }
478
479
    /**
480
     * Attempt to authenticate a user using the given credentials.
481
     *
482
     * @param array $credentials
483
     * @param bool  $remember
484
     * @param bool  $login
485
     *
486
     * @return string
487
     */
488
    public function attempt(array $credentials = [], $remember = false, $login = true)
489
    {
490
        // Fire the authentication attempt event
491
        $this->events->fire('rinvex.fort.auth.attempt', [$credentials, $remember, $login]);
492
493
        $this->lastAttempted = $user = $this->provider->findByCredentials($credentials);
0 ignored issues
show
Bug introduced by
The method findByCredentials() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
494
495
        // Login throttling
496
        $throttles = config('rinvex.fort.throttle.enabled');
497
        $lockedOut = $this->hasTooManyLoginAttempts($this->getRequest());
498
499
        if ($throttles && $lockedOut) {
500
            // Fire the authentication lockout event (only if user exists)
501
            if ($user) {
502
                $this->events->fire('rinvex.fort.auth.lockout', [$this->getRequest()]);
503
            }
504
505
            return static::AUTH_LOCKED_OUT;
506
        }
507
508
        // If an implementation of UserInterface was returned, we'll ask the provider
509
        // to validate the user against the given credentials, and if they are in
510
        // fact valid we'll log the users into the application and return true.
511
        if ($this->hasValidCredentials($user, $credentials)) {
512
            // Check if unverified
513
            if (config('rinvex.fort.verification.required') && ! $user->isEmailVerified()) {
514
                // Fire the authentication unverified event
515
                $this->events->fire('rinvex.fort.auth.unverified', [$user]);
516
517
                // Verification required
518
                return static::AUTH_UNVERIFIED;
519
            }
520
521
            $totp  = array_get($user->getTwoFactor(), 'totp.enabled');
522
            $phone = array_get($user->getTwoFactor(), 'phone.enabled');
523
524
            // Enforce Two-Factor authentication
525
            if ($totp || $phone) {
526
                // Update user persistence
527
                $this->updatePersistence($user->id, $this->session->getId(), true);
528
529
                $this->session->flash('rinvex.fort.twofactor.methods', ['totp' => $totp, 'phone' => $phone]);
530
                $this->session->flash('rinvex.fort.twofactor.remember', $remember);
531
                $this->session->flash('rinvex.fort.twofactor.persistence', $this->session->getId());
532
533
                // Fire the Two-Factor authentication required event
534
                $this->events->fire('rinvex.fort.twofactor.required', [$user]);
535
536
                return static::AUTH_TWOFACTOR_REQUIRED;
537
            }
538
539
            // If Two-Factor enabled, `attempt` method always returns false,
540
            // use `login` or `loginUsingId` methods to login users in such case.
541
            if ($login) {
542
                return $this->login($user, $remember);
543
            }
544
545
            // Valid credentials, clear login attempts
546
            if ($throttles) {
547
                $this->clearLoginAttempts($this->getRequest());
548
            }
549
550
            // Fire the authentication valid event
551
            $this->events->fire('rinvex.fort.auth.valid', [$credentials, $remember]);
552
553
            return static::AUTH_VALID;
554
        }
555
556
        // Invalid credentials, increment login attempts
557
        if ($throttles && ! $lockedOut) {
558
            $this->incrementLoginAttempts($this->getRequest());
559
        }
560
561
        // Clear Two-Factor authentication attempts
562
        $this->clearTwoFactor();
563
564
        // Fire the authentication failed event
565
        $this->events->fire('rinvex.fort.auth.failed', [$credentials, $remember]);
566
567
        return static::AUTH_FAILED;
568
    }
569
570
    /**
571
     * Determine if the user matches the credentials.
572
     *
573
     * @param mixed $user
574
     * @param array $credentials
575
     *
576
     * @return bool
577
     */
578
    protected function hasValidCredentials($user, $credentials)
579
    {
580
        return ! is_null($user) && $this->provider->validateCredentials($user, $credentials);
581
    }
582
583
    /**
584
     * Log a user into the application.
585
     *
586
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
587
     * @param bool                                           $remember
588
     * @param string                                         $persistence
0 ignored issues
show
Documentation introduced by
Should the type for parameter $persistence not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
589
     *
590
     * @return string
591
     */
592
    public function login(AuthenticatableContract $user, $remember = false, $force = false, $persistence = null)
593
    {
594
        // Check if moderated
595
        if ($user->moderated && ! $force) {
0 ignored issues
show
Bug introduced by
Accessing moderated on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
596
            // Fire the authentication moderated event
597
            $this->events->fire('rinvex.fort.auth.moderated', [$user]);
598
599
            // Activation required
600
            return static::AUTH_MODERATED;
601
        }
602
603
        $this->updateSession($user->getAuthIdentifier());
604
605
        // If the user should be permanently "remembered" by the application we will
606
        // queue a permanent cookie that contains the encrypted copy of the user
607
        // identifier. We will then decrypt this later to retrieve the users.
608
        if ($remember) {
609
            $this->createRememberTokenIfDoesntExist($user);
610
611
            $this->queueRecallerCookie($user);
612
        }
613
614
        // Check persistence mode
615
        if (config('rinvex.fort.persistence') === 'single') {
616
            $user->persistences()->delete();
617
        }
618
619
        // Update user last login datetime
620
        $this->provider->update($user->id, ['login_at' => new Carbon()]);
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
The method update() does not exist on Illuminate\Contracts\Auth\UserProvider. Did you maybe mean updateRememberToken()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
621
622
        // Update user persistence
623
        $this->updatePersistence($user->id, $persistence ?: $this->session->getId(), false);
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
624
625
        // Login successful, clear login attempts
626
        if (config('rinvex.fort.throttle.enabled')) {
627
            $this->clearLoginAttempts($this->getRequest());
628
        }
629
630
        // Clear Two-Factor authentication attempts
631
        $this->clearTwoFactor();
632
633
        // Fire the authentication login event
634
        $this->events->fire('rinvex.fort.auth.login', [$user, $remember]);
635
636
        $this->setUser($user);
637
638
        return static::AUTH_LOGIN;
639
    }
640
641
    /**
642
     * Update the session with the given ID.
643
     *
644
     * @param string $id
645
     *
646
     * @return void
647
     */
648
    protected function updateSession($id)
649
    {
650
        $this->session->set($this->getName(), $id);
651
652
        $this->session->migrate(true);
653
    }
654
655
    /**
656
     * Log the given user ID into the application.
657
     *
658
     * @param mixed $id
659
     * @param bool  $remember
660
     *
661
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|false
662
     */
663
    public function loginUsingId($id, $remember = false)
664
    {
665
        $user = $this->provider->find($id);
0 ignored issues
show
Bug introduced by
The method find() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
666
667
        if (! is_null($user)) {
668
            $this->login($user, $remember);
669
670
            return $user;
671
        }
672
673
        return false;
674
    }
675
676
    /**
677
     * Log the given user ID into the application without sessions or cookies.
678
     *
679
     * @param mixed $id
680
     *
681
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|false
682
     */
683
    public function onceUsingId($id)
684
    {
685
        $user = $this->provider->find($id);
0 ignored issues
show
Bug introduced by
The method find() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
686
687
        if (! is_null($user)) {
688
            $this->setUser($user);
689
690
            return $user;
691
        }
692
693
        return false;
694
    }
695
696
    /**
697
     * Queue the recaller cookie into the cookie jar.
698
     *
699
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
700
     *
701
     * @return void
702
     */
703
    protected function queueRecallerCookie(AuthenticatableContract $user)
704
    {
705
        $value = $user->getAuthIdentifier().'|'.$user->getRememberToken();
706
707
        $this->getCookieJar()->queue($this->createRecaller($value));
0 ignored issues
show
Unused Code introduced by
The call to QueueingFactory::queue() has too many arguments starting with $this->createRecaller($value).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
708
    }
709
710
    /**
711
     * Create a "remember me" cookie for a given ID.
712
     *
713
     * @param string $value
714
     *
715
     * @return \Symfony\Component\HttpFoundation\Cookie
716
     */
717
    protected function createRecaller($value)
718
    {
719
        return $this->getCookieJar()->forever($this->getRecallerName(), $value);
720
    }
721
722
    /**
723
     * Log the user out of the application.
724
     *
725
     * @return void
0 ignored issues
show
Documentation introduced by
Should the return type not be string?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
726
     */
727
    public function logout()
728
    {
729
        $this->logoutAttempted = true;
730
731
        $user = $this->user();
732
733
        // If we have an event dispatcher instance, we can fire off the logout event
734
        // so any further processing can be done. This allows the developer to be
735
        // listening for anytime a user signs out of this application manually.
736
        $this->clearUserDataFromStorage();
737
738
        if (! is_null($this->user)) {
739
            $this->refreshRememberToken($user);
0 ignored issues
show
Documentation introduced by
$user is of type null|object<Illuminate\C...s\Auth\Authenticatable>, but the function expects a object<Rinvex\Fort\Contr...uthenticatableContract>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
740
        }
741
742
        // Delete user persistence
743
        app('rinvex.fort.persistence')->delete($this->session->getId());
744
745
        // Fire the authentication logout event
746
        $this->events->fire('rinvex.fort.auth.logout', [$user]);
747
748
        // Once we have fired the logout event we will clear the users out of memory
749
        // so they are no longer available as the user is no longer considered as
750
        // being signed into this application and should not be available here.
751
        $this->user = null;
752
753
        $this->loggedOut = true;
754
755
        return static::AUTH_LOGOUT;
756
    }
757
758
    /**
759
     * Remove the user data from the session and cookies.
760
     *
761
     * @return void
762
     */
763
    protected function clearUserDataFromStorage()
764
    {
765
        $this->session->remove($this->getName());
766
767
        if (! is_null($this->getRecaller())) {
768
            $recaller = $this->getRecallerName();
769
770
            $this->getCookieJar()->queue($this->getCookieJar()->forget($recaller));
0 ignored issues
show
Unused Code introduced by
The call to QueueingFactory::queue() has too many arguments starting with $this->getCookieJar()->forget($recaller).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
771
        }
772
    }
773
774
    /**
775
     * Refresh the "remember me" token for the user.
776
     *
777
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
778
     *
779
     * @return void
780
     */
781
    protected function refreshRememberToken(AuthenticatableContract $user)
782
    {
783
        $user->setRememberToken($token = Str::random(60));
784
785
        $this->provider->updateRememberToken($user, $token);
786
    }
787
788
    /**
789
     * Create a new "remember me" token for the user if one doesn't already exist.
790
     *
791
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
792
     *
793
     * @return void
794
     */
795
    protected function createRememberTokenIfDoesntExist(AuthenticatableContract $user)
796
    {
797
        if (empty($user->getRememberToken())) {
798
            $this->refreshRememberToken($user);
799
        }
800
    }
801
802
    /**
803
     * Get the cookie creator instance used by the guard.
804
     *
805
     * @return \Illuminate\Contracts\Cookie\QueueingFactory
806
     *
807
     * @throws \RuntimeException
808
     */
809
    public function getCookieJar()
810
    {
811
        if (! isset($this->cookie)) {
812
            throw new RuntimeException('Cookie jar has not been set.');
813
        }
814
815
        return $this->cookie;
816
    }
817
818
    /**
819
     * Set the cookie creator instance used by the guard.
820
     *
821
     * @param \Illuminate\Contracts\Cookie\QueueingFactory $cookie
822
     *
823
     * @return void
824
     */
825
    public function setCookieJar(CookieJar $cookie)
826
    {
827
        $this->cookie = $cookie;
828
    }
829
830
    /**
831
     * Get the event dispatcher instance.
832
     *
833
     * @return \Illuminate\Contracts\Events\Dispatcher
834
     */
835
    public function getDispatcher()
836
    {
837
        return $this->events;
838
    }
839
840
    /**
841
     * Set the event dispatcher instance.
842
     *
843
     * @param \Illuminate\Contracts\Events\Dispatcher $events
844
     *
845
     * @return void
846
     */
847
    public function setDispatcher(Dispatcher $events)
848
    {
849
        $this->events = $events;
850
    }
851
852
    /**
853
     * Get the session store used by the guard.
854
     *
855
     * @return \Illuminate\Session\Store
856
     */
857
    public function getSession()
858
    {
859
        return $this->session;
860
    }
861
862
    /**
863
     * Get the user provider used by the guard.
864
     *
865
     * @return \Rinvex\Fort\Contracts\UserRepositoryContract
0 ignored issues
show
Documentation introduced by
Should the return type not be \Illuminate\Contracts\Auth\UserProvider?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
866
     */
867
    public function getProvider()
868
    {
869
        return $this->provider;
870
    }
871
872
    /**
873
     * Set the user provider used by the guard.
874
     *
875
     * @param \Rinvex\Fort\Contracts\UserRepositoryContract $provider
876
     *
877
     * @return void
878
     */
879
    public function setProvider(UserRepositoryContract $provider)
880
    {
881
        $this->provider = $provider;
0 ignored issues
show
Documentation Bug introduced by
It seems like $provider of type object<Rinvex\Fort\Contr...UserRepositoryContract> is incompatible with the declared type object<Illuminate\Contracts\Auth\UserProvider> of property $provider.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
882
    }
883
884
    /**
885
     * Return the currently cached user.
886
     *
887
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|null
0 ignored issues
show
Documentation introduced by
Should the return type not be \Illuminate\Contracts\Auth\Authenticatable?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
888
     */
889
    public function getUser()
890
    {
891
        return $this->user;
892
    }
893
894
    /**
895
     * Set the current user.
896
     *
897
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
898
     *
899
     * @return void
0 ignored issues
show
Documentation introduced by
Should the return type not be SessionGuard?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
900
     */
901
    public function setUser(AuthenticatableContract $user)
902
    {
903
        $this->user = $user;
904
905
        $this->loggedOut = false;
906
907
        // Fire the authenticated event
908
        $this->events->fire('rinvex.fort.auth.user', [$user]);
909
910
        return $this;
911
    }
912
913
    /**
914
     * Get the current request instance.
915
     *
916
     * @return \Illuminate\Http\Request
917
     */
918
    public function getRequest()
919
    {
920
        return $this->request ?: Request::capture();
921
    }
922
923
    /**
924
     * Set the current request instance.
925
     *
926
     * @param \Illuminate\Http\Request $request
927
     *
928
     * @return $this
929
     */
930
    public function setRequest(Request $request)
0 ignored issues
show
Bug introduced by
You have injected the Request via parameter $request. This is generally not recommended as there might be multiple instances during a request cycle (f.e. when using sub-requests). Instead, it is recommended to inject the RequestStack and retrieve the current request each time you need it via getCurrentRequest().
Loading history...
931
    {
932
        $this->request = $request;
933
934
        return $this;
935
    }
936
937
    /**
938
     * Get the last user we attempted to authenticate.
939
     *
940
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract
941
     */
942
    public function getLastAttempted()
943
    {
944
        return $this->lastAttempted;
945
    }
946
947
    /**
948
     * Get a unique identifier for the auth session value.
949
     *
950
     * @return string
951
     */
952
    public function getName()
953
    {
954
        return 'login_'.$this->name.'_'.sha1(static::class);
955
    }
956
957
    /**
958
     * Get the name of the cookie used to store the "recaller".
959
     *
960
     * @return string
961
     */
962
    public function getRecallerName()
963
    {
964
        return 'remember_'.$this->name.'_'.sha1(static::class);
965
    }
966
967
    /**
968
     * Determine if the user was authenticated via "remember me" cookie.
969
     *
970
     * @return bool
971
     */
972
    public function viaRemember()
973
    {
974
        return $this->viaRemember;
975
    }
976
977
    /**
978
     * Clear Two-Factor authentication attempts.
979
     *
980
     * @return void
981
     */
982
    protected function clearTwoFactor()
983
    {
984
        $this->session->forget('rinvex.fort.twofactor.methods');
985
        $this->session->forget('rinvex.fort.twofactor.remember');
986
        $this->session->forget('rinvex.fort.twofactor.persistence');
987
    }
988
989
    /**
990
     * Remember Two-Factor authentication attempts.
991
     *
992
     * @return void
993
     */
994
    public function rememberTwoFactor()
995
    {
996
        $this->session->keep([
997
            'rinvex.fort.twofactor.methods',
998
            'rinvex.fort.twofactor.remember',
999
            'rinvex.fort.twofactor.persistence',
1000
        ]);
1001
    }
1002
1003
    /**
1004
     * Update user persistence.
1005
     *
1006
     * @param int    $id
1007
     * @param string $token
1008
     * @param bool   $attempt
1009
     *
1010
     * @return void
1011
     */
1012
    protected function updatePersistence($id, $token, $attempt)
1013
    {
1014
        $agent = request()->server('HTTP_USER_AGENT');
1015
        $ip    = request()->ip();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ip. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1016
1017
        // Delete previous user persistence
1018
        app('rinvex.fort.persistence')->whereAttempt(1)->delete($token);
1019
1020
        // Create new user persistence
1021
        app('rinvex.fort.persistence')->create([
1022
            'user_id'    => $id,
1023
            'token'      => $this->session->getId(),
1024
            'attempt'    => $attempt,
1025
            'agent'      => $agent,
1026
            'ip'         => $ip,
1027
            'created_at' => new Carbon(),
1028
        ]);
1029
    }
1030
1031
    /**
1032
     * Verify Two-Factor authentication.
1033
     *
1034
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
1035
     * @param string                                         $token
1036
     *
1037
     * @return string
1038
     */
1039
    public function attemptTwoFactor(AuthenticatableContract $user, $token)
1040
    {
1041
        // Prepare required variables
1042
        $validBackup = false;
1043
1044
        // Verify Two-Factor authentication, then login user
1045
        if (session('rinvex.fort.twofactor.persistence') && ($this->isValidTwoFactorTotp($user, $token) || $this->isValidTwoFactorPhone($user, $token) || $validBackup = $this->isValidTwoFactorBackup($user, $token))) {
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 217 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
1046
            $this->login($user, session('rinvex.fort.twofactor.remember'), session('rinvex.fort.twofactor.persistence'));
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 121 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
1047
1048
            if ($validBackup) {
1049
                $this->invalidateTwoFactorBackup($user, $token);
1050
            }
1051
1052
            return static::AUTH_LOGIN;
1053
        }
1054
1055
        // This is NOT login attempt, it's just account update -> phone verification
1056
        if (! session('rinvex.fort.twofactor.persistence') && $this->isValidTwoFactorPhone($user, $token)) {
1057
            return static::AUTH_PHONE_VERIFIED;
1058
        }
1059
1060
        return static::AUTH_TWOFACTOR_FAILED;
1061
    }
1062
1063
    /**
1064
     * Invalidate given backup code for the given user.
1065
     *
1066
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
1067
     * @param                                                $token
1068
     *
1069
     * @return void
1070
     */
1071
    protected function invalidateTwoFactorBackup(AuthenticatableContract $user, $token)
1072
    {
1073
        $settings = $user->getTwoFactor();
1074
        $backup   = array_get($settings, 'totp.backup');
1075
1076
        unset($backup[array_search($token, $backup)]);
1077
1078
        array_set($settings, 'totp.backup', $backup);
1079
1080
        // Update Two-Factor OTP backup codes
1081
        $this->provider->update($user->id, [
0 ignored issues
show
Bug introduced by
Accessing id on the interface Rinvex\Fort\Contracts\AuthenticatableContract suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
The method update() does not exist on Illuminate\Contracts\Auth\UserProvider. Did you maybe mean updateRememberToken()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
1082
            'two_factor' => $settings,
1083
        ]);
1084
    }
1085
1086
    /**
1087
     * Determine if the given token is a valid Two-Factor Phone token.
1088
     *
1089
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
1090
     * @param                                                $token
1091
     *
1092
     * @return bool
1093
     */
1094
    protected function isValidTwoFactorPhone(AuthenticatableContract $user, $token)
1095
    {
1096
        $authy = app(TwoFactorAuthyProvider::class);
1097
1098
        return strlen($token) === 7 && isset(session('rinvex.fort.twofactor.methods')['phone']) && $authy->tokenIsValid($user, $token);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 135 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
1099
    }
1100
1101
    /**
1102
     * Determine if the given token is a valid Two-Factor Backup code.
1103
     *
1104
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
1105
     * @param                                                $token
1106
     *
1107
     * @return bool
1108
     */
1109
    protected function isValidTwoFactorBackup(AuthenticatableContract $user, $token)
1110
    {
1111
        // Fire the Two-Factor TOTP backup verify start event
1112
        $this->events->fire('rinvex.fort.twofactor.backup.verify.start', [$user, $token]);
1113
1114
        $backup = array_get($user->getTwoFactor(), 'totp.backup', []);
1115
        $result = strlen($token) === 10 && in_array($token, $backup);
1116
1117
        if ($result) {
1118
            // Fire the Two-Factor TOTP backup verify success event
1119
            $this->events->fire('rinvex.fort.twofactor.backup.verify.success', [$user, $token]);
1120
        } else {
1121
            // Fire the Two-Factor TOTP backup verify failed event
1122
            $this->events->fire('rinvex.fort.twofactor.backup.verify.failed', [$user, $token]);
1123
        }
1124
1125
        return $result;
1126
    }
1127
1128
    /**
1129
     * Determine if the given token is a valid Two-Factor TOTP token.
1130
     *
1131
     * @param \Rinvex\Fort\Contracts\AuthenticatableContract $user
1132
     * @param                                                $token
1133
     *
1134
     * @return bool
1135
     */
1136
    protected function isValidTwoFactorTotp(AuthenticatableContract $user, $token)
1137
    {
1138
        $totp   = app(TwoFactorTotpProvider::class);
1139
        $secret = array_get($user->getTwoFactor(), 'totp.secret');
1140
1141
        return strlen($token) === 6 && isset(session('rinvex.fort.twofactor.methods')['totp']) && $totp->verifyKey($secret, $token);
0 ignored issues
show
Coding Style introduced by
This line exceeds maximum limit of 120 characters; contains 132 characters

Overly long lines are hard to read on any screen. Most code styles therefor impose a maximum limit on the number of characters in a line.

Loading history...
1142
    }
1143
1144
    /**
1145
     * Register a new user.
1146
     *
1147
     * @param array $credentials
1148
     *
1149
     * @return string
1150
     */
1151
    public function register(array $credentials)
1152
    {
1153
        // Fire the register start event
1154
        $this->events->fire('rinvex.fort.register.start', [$credentials]);
1155
1156
        // Prepare registration data
1157
        $credentials['password']  = bcrypt($credentials['password']);
1158
        $credentials['moderated'] = config('rinvex.fort.registration.moderated');
1159
1160
        // Create new user
1161
        $user = $this->provider->create($credentials);
0 ignored issues
show
Bug introduced by
The method create() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1162
1163
        // Fire the register success event
1164
        $this->events->fire('rinvex.fort.register.success', [$user]);
1165
1166
        // Send verification if required
1167
        if (config('rinvex.fort.verification.required')) {
1168
            return app('rinvex.fort.verifier')->broker()->sendVerificationLink(['email' => $credentials['email']]);
1169
        }
1170
1171
        // Registration completed successfully
1172
        return static::AUTH_REGISTERED;
1173
    }
1174
1175
    /**
1176
     * Register a new social user.
1177
     *
1178
     * @param array $credentials
1179
     *
1180
     * @return string
1181
     */
1182
    public function registerSocialite(array $credentials)
1183
    {
1184
        // Fire the register social start event
1185
        $this->events->fire('rinvex.fort.register.social.start', [$credentials]);
1186
1187
        // Prepare registration data
1188
        $credentials['password']  = bcrypt(str_random());
1189
        $credentials['moderated'] = config('rinvex.fort.registration.moderated');
1190
1191
        // Create new user
1192
        $user = $this->provider->create($credentials);
0 ignored issues
show
Bug introduced by
The method create() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1193
1194
        // Fire the register social success event
1195
        $this->events->fire('rinvex.fort.register.social.success', [$user]);
1196
1197
        // Registration completed successfully
1198
        return $user;
1199
    }
1200
1201
    /**
1202
     * Pull a persistence from the repository by its token.
1203
     *
1204
     * @return \Rinvex\Fort\Repositories\PersistenceRepository
1205
     */
1206
    public function getPersistenceByToken($token)
1207
    {
1208
        return app('rinvex.fort.persistence')->findByToken($token);
1209
    }
1210
1211
    /**
1212
     * Pull a user from the repository by its session ID.
1213
     *
1214
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|null
1215
     */
1216
    public function getUserBySession()
1217
    {
1218
        return ! is_null($id = $this->session->get($this->getName())) ? $this->provider->find($id) : null;
0 ignored issues
show
Bug introduced by
The method find() does not seem to exist on object<Illuminate\Contracts\Auth\UserProvider>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1219
    }
1220
1221
    /**
1222
     * Pull a user from the repository by its cookie remember me ID.
1223
     *
1224
     * @return \Rinvex\Fort\Contracts\AuthenticatableContract|null
1225
     */
1226
    public function getUserByCookie()
1227
    {
1228
        return ! is_null($recaller = $this->getRecaller()) ? $this->getUserByRecaller($recaller) : null;
1229
    }
1230
}
1231