OneTimeTokensGenerator::invalidateUnused()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
namespace ArgentCrusade\Stronghold;
4
5
use ArgentCrusade\Stronghold\Contracts\OneTimeTokensRepositoryInterface;
6
use ArgentCrusade\Stronghold\Events\OneTimeTokenCreated;
7
use Carbon\Carbon;
8
use Illuminate\Contracts\Auth\Authenticatable;
9
use Illuminate\Database\Eloquent\Model;
10
use Illuminate\Support\Str;
11
12
class OneTimeTokensGenerator
13
{
14
    /** @var OneTimeTokensRepositoryInterface */
15
    protected $repository;
16
17
    /** @var int */
18
    protected $min;
19
20
    /** @var int */
21
    protected $max;
22
23
    /**
24
     * OneTimeTokensGenerator constructor.
25
     *
26
     * @param OneTimeTokensRepositoryInterface $repository
27
     * @param int                              $min
28
     * @param int                              $max
29
     */
30
    public function __construct(OneTimeTokensRepositoryInterface $repository, int $min = 1000, int $max = 9999)
31
    {
32
        $this->repository = $repository;
33
34
        $this->using($min, $max);
35
    }
36
37
    /**
38
     * Refresh min & max values.
39
     *
40
     * @param int $min
41
     * @param int $max
42
     *
43
     * @return OneTimeTokensGenerator
44
     */
45
    public function using(int $min, int $max)
46
    {
47
        $this->min = $min;
48
        $this->max = $max;
49
50
        return $this;
51
    }
52
53
    /**
54
     * Generate one time token for the given user.
55
     *
56
     * @param Authenticatable|Model|mixed $user
57
     * @param string                      $operation
58
     * @param string                      $payload   = null
59
     *
60
     * @return OneTimeToken|null
61
     */
62
    public function generate($user, string $operation, string $payload = null)
63
    {
64
        $token = $this->findUnusedTokenFor($user, $operation);
65
66
        if (!is_null($token)) {
67
            return $token;
68
        }
69
70
        return $this->createToken($user, $operation, $payload);
71
    }
72
73
    /**
74
     * Invalidate unused tokens for given user & optional operation.
75
     *
76
     * @param Authenticatable|Model|mixed $user
77
     * @param string|null                 $operation
78
     *
79
     * @return int
80
     */
81
    public function invalidateUnused($user, string $operation = null)
82
    {
83
        return $this->repository->deleteUnusedFor($this->getUserIdentifier($user), $operation);
84
    }
85
86
    /**
87
     * Create new one time token.
88
     *
89
     * @param Authenticatable|Model|mixed $user
90
     * @param string                      $operation
91
     * @param string                      $payload   = null
92
     *
93
     * @return OneTimeToken
94
     */
95
    protected function createToken($user, string $operation, string $payload = null)
96
    {
97
        $token = $this->repository->create([
98
            'user_id' => $this->getUserIdentifier($user),
99
            'operation' => $operation,
100
            'identifier' => Str::random(32),
101
            'code' => mt_rand($this->min, $this->max),
102
            'payload' => $payload,
103
            'expires_at' => Carbon::now()->addMinutes(15),
104
            'used_at' => null,
105
        ]);
106
107
        event(new OneTimeTokenCreated($token));
108
109
        return $token;
110
    }
111
112
    /**
113
     * Find unused token for the given user.
114
     *
115
     * @param Authenticatable|Model|mixed $user
116
     * @param string                      $operation
117
     *
118
     * @return OneTimeToken|null
119
     */
120
    protected function findUnusedTokenFor($user, string $operation)
121
    {
122
        return $this->repository->firstUnusedFor($this->getUserIdentifier($user), $operation);
123
    }
124
125
    /**
126
     * Get user identifier from given argument.
127
     *
128
     * @param Authenticatable|Model|mixed $user
129
     *
130
     * @return mixed
131
     */
132
    protected function getUserIdentifier($user)
133
    {
134
        if ($user instanceof Authenticatable) {
135
            return $user->getAuthIdentifier();
136
        } elseif ($user instanceof Model) {
137
            return $user->getKey();
138
        } elseif (is_scalar($user)) {
139
            return $user;
140
        }
141
142
        throw new \UnexpectedValueException('User must be an instance of Authenticatable, Model or scalar value.');
143
    }
144
}
145