]> BookStack Code Mirror - bookstack/blob - app/Auth/Access/UserTokenService.php
Mail: updated peer verify option name and added test
[bookstack] / app / Auth / Access / UserTokenService.php
1 <?php
2
3 namespace BookStack\Auth\Access;
4
5 use BookStack\Auth\User;
6 use BookStack\Exceptions\UserTokenExpiredException;
7 use BookStack\Exceptions\UserTokenNotFoundException;
8 use Carbon\Carbon;
9 use Illuminate\Support\Facades\DB;
10 use Illuminate\Support\Str;
11 use stdClass;
12
13 class UserTokenService
14 {
15     /**
16      * Name of table where user tokens are stored.
17      *
18      * @var string
19      */
20     protected $tokenTable = 'user_tokens';
21
22     /**
23      * Token expiry time in hours.
24      *
25      * @var int
26      */
27     protected $expiryTime = 24;
28
29     /**
30      * Delete all email confirmations that belong to a user.
31      *
32      * @param User $user
33      *
34      * @return mixed
35      */
36     public function deleteByUser(User $user)
37     {
38         return DB::table($this->tokenTable)
39             ->where('user_id', '=', $user->id)
40             ->delete();
41     }
42
43     /**
44      * Get the user id from a token, while check the token exists and has not expired.
45      *
46      * @param string $token
47      *
48      * @throws UserTokenNotFoundException
49      * @throws UserTokenExpiredException
50      *
51      * @return int
52      */
53     public function checkTokenAndGetUserId(string $token): int
54     {
55         $entry = $this->getEntryByToken($token);
56
57         if (is_null($entry)) {
58             throw new UserTokenNotFoundException('Token "' . $token . '" not found');
59         }
60
61         if ($this->entryExpired($entry)) {
62             throw new UserTokenExpiredException("Token of id {$entry->id} has expired.", $entry->user_id);
63         }
64
65         return $entry->user_id;
66     }
67
68     /**
69      * Creates a unique token within the email confirmation database.
70      *
71      * @return string
72      */
73     protected function generateToken(): string
74     {
75         $token = Str::random(24);
76         while ($this->tokenExists($token)) {
77             $token = Str::random(25);
78         }
79
80         return $token;
81     }
82
83     /**
84      * Generate and store a token for the given user.
85      *
86      * @param User $user
87      *
88      * @return string
89      */
90     protected function createTokenForUser(User $user): string
91     {
92         $token = $this->generateToken();
93         DB::table($this->tokenTable)->insert([
94             'user_id'    => $user->id,
95             'token'      => $token,
96             'created_at' => Carbon::now(),
97             'updated_at' => Carbon::now(),
98         ]);
99
100         return $token;
101     }
102
103     /**
104      * Check if the given token exists.
105      *
106      * @param string $token
107      *
108      * @return bool
109      */
110     protected function tokenExists(string $token): bool
111     {
112         return DB::table($this->tokenTable)
113             ->where('token', '=', $token)->exists();
114     }
115
116     /**
117      * Get a token entry for the given token.
118      *
119      * @param string $token
120      *
121      * @return object|null
122      */
123     protected function getEntryByToken(string $token)
124     {
125         return DB::table($this->tokenTable)
126             ->where('token', '=', $token)
127             ->first();
128     }
129
130     /**
131      * Check if the given token entry has expired.
132      *
133      * @param stdClass $tokenEntry
134      *
135      * @return bool
136      */
137     protected function entryExpired(stdClass $tokenEntry): bool
138     {
139         return Carbon::now()->subHours($this->expiryTime)
140             ->gt(new Carbon($tokenEntry->created_at));
141     }
142 }