3 namespace BookStack\Access;
5 use BookStack\Exceptions\UserTokenExpiredException;
6 use BookStack\Exceptions\UserTokenNotFoundException;
7 use BookStack\Users\Models\User;
9 use Illuminate\Support\Facades\DB;
10 use Illuminate\Support\Str;
13 class UserTokenService
16 * Name of table where user tokens are stored.
18 protected string $tokenTable = 'user_tokens';
21 * Token expiry time in hours.
23 protected int $expiryTime = 24;
26 * Delete all tokens that belong to a user.
28 public function deleteByUser(User $user): void
30 DB::table($this->tokenTable)
31 ->where('user_id', '=', $user->id)
36 * Get the user id from a token, while checking the token exists and has not expired.
38 * @throws UserTokenNotFoundException
39 * @throws UserTokenExpiredException
41 public function checkTokenAndGetUserId(string $token): int
43 $entry = $this->getEntryByToken($token);
45 if (is_null($entry)) {
46 throw new UserTokenNotFoundException('Token "' . $token . '" not found');
49 if ($this->entryExpired($entry)) {
50 throw new UserTokenExpiredException("Token of id {$entry->id} has expired.", $entry->user_id);
53 return $entry->user_id;
57 * Creates a unique token within the email confirmation database.
59 protected function generateToken(): string
61 $token = Str::random(24);
62 while ($this->tokenExists($token)) {
63 $token = Str::random(25);
70 * Generate and store a token for the given user.
72 protected function createTokenForUser(User $user): string
74 $token = $this->generateToken();
75 DB::table($this->tokenTable)->insert([
76 'user_id' => $user->id,
78 'created_at' => Carbon::now(),
79 'updated_at' => Carbon::now(),
86 * Check if the given token exists.
88 protected function tokenExists(string $token): bool
90 return DB::table($this->tokenTable)
91 ->where('token', '=', $token)->exists();
95 * Get a token entry for the given token.
97 protected function getEntryByToken(string $token): ?stdClass
99 return DB::table($this->tokenTable)
100 ->where('token', '=', $token)
105 * Check if the given token entry has expired.
107 protected function entryExpired(stdClass $tokenEntry): bool
109 return Carbon::now()->subHours($this->expiryTime)
110 ->gt(new Carbon($tokenEntry->created_at));