]> BookStack Code Mirror - bookstack/blob - app/Access/UserTokenService.php
Played around with a new app structure
[bookstack] / app / Access / UserTokenService.php
1 <?php
2
3 namespace BookStack\Access;
4
5 use BookStack\Exceptions\UserTokenExpiredException;
6 use BookStack\Exceptions\UserTokenNotFoundException;
7 use BookStack\Users\Models\User;
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     protected string $tokenTable = 'user_tokens';
19
20     /**
21      * Token expiry time in hours.
22      */
23     protected int $expiryTime = 24;
24
25     /**
26      * Delete all tokens that belong to a user.
27      */
28     public function deleteByUser(User $user): void
29     {
30         DB::table($this->tokenTable)
31             ->where('user_id', '=', $user->id)
32             ->delete();
33     }
34
35     /**
36      * Get the user id from a token, while checking the token exists and has not expired.
37      *
38      * @throws UserTokenNotFoundException
39      * @throws UserTokenExpiredException
40      */
41     public function checkTokenAndGetUserId(string $token): int
42     {
43         $entry = $this->getEntryByToken($token);
44
45         if (is_null($entry)) {
46             throw new UserTokenNotFoundException('Token "' . $token . '" not found');
47         }
48
49         if ($this->entryExpired($entry)) {
50             throw new UserTokenExpiredException("Token of id {$entry->id} has expired.", $entry->user_id);
51         }
52
53         return $entry->user_id;
54     }
55
56     /**
57      * Creates a unique token within the email confirmation database.
58      */
59     protected function generateToken(): string
60     {
61         $token = Str::random(24);
62         while ($this->tokenExists($token)) {
63             $token = Str::random(25);
64         }
65
66         return $token;
67     }
68
69     /**
70      * Generate and store a token for the given user.
71      */
72     protected function createTokenForUser(User $user): string
73     {
74         $token = $this->generateToken();
75         DB::table($this->tokenTable)->insert([
76             'user_id'    => $user->id,
77             'token'      => $token,
78             'created_at' => Carbon::now(),
79             'updated_at' => Carbon::now(),
80         ]);
81
82         return $token;
83     }
84
85     /**
86      * Check if the given token exists.
87      */
88     protected function tokenExists(string $token): bool
89     {
90         return DB::table($this->tokenTable)
91             ->where('token', '=', $token)->exists();
92     }
93
94     /**
95      * Get a token entry for the given token.
96      */
97     protected function getEntryByToken(string $token): ?stdClass
98     {
99         return DB::table($this->tokenTable)
100             ->where('token', '=', $token)
101             ->first();
102     }
103
104     /**
105      * Check if the given token entry has expired.
106      */
107     protected function entryExpired(stdClass $tokenEntry): bool
108     {
109         return Carbon::now()->subHours($this->expiryTime)
110             ->gt(new Carbon($tokenEntry->created_at));
111     }
112 }