3 namespace BookStack\Auth\Access;
5 use BookStack\Auth\User;
6 use BookStack\Exceptions\UserTokenExpiredException;
7 use BookStack\Exceptions\UserTokenNotFoundException;
9 use Illuminate\Database\Connection as Database;
10 use Illuminate\Support\Str;
13 class UserTokenService
16 * Name of table where user tokens are stored.
20 protected $tokenTable = 'user_tokens';
23 * Token expiry time in hours.
27 protected $expiryTime = 24;
32 * UserTokenService constructor.
36 public function __construct(Database $db)
42 * Delete all email confirmations that belong to a user.
48 public function deleteByUser(User $user)
50 return $this->db->table($this->tokenTable)
51 ->where('user_id', '=', $user->id)
56 * Get the user id from a token, while check the token exists and has not expired.
58 * @param string $token
60 * @throws UserTokenNotFoundException
61 * @throws UserTokenExpiredException
65 public function checkTokenAndGetUserId(string $token): int
67 $entry = $this->getEntryByToken($token);
69 if (is_null($entry)) {
70 throw new UserTokenNotFoundException('Token "' . $token . '" not found');
73 if ($this->entryExpired($entry)) {
74 throw new UserTokenExpiredException("Token of id {$entry->id} has expired.", $entry->user_id);
77 return $entry->user_id;
81 * Creates a unique token within the email confirmation database.
85 protected function generateToken(): string
87 $token = Str::random(24);
88 while ($this->tokenExists($token)) {
89 $token = Str::random(25);
96 * Generate and store a token for the given user.
102 protected function createTokenForUser(User $user): string
104 $token = $this->generateToken();
105 $this->db->table($this->tokenTable)->insert([
106 'user_id' => $user->id,
108 'created_at' => Carbon::now(),
109 'updated_at' => Carbon::now(),
116 * Check if the given token exists.
118 * @param string $token
122 protected function tokenExists(string $token): bool
124 return $this->db->table($this->tokenTable)
125 ->where('token', '=', $token)->exists();
129 * Get a token entry for the given token.
131 * @param string $token
133 * @return object|null
135 protected function getEntryByToken(string $token)
137 return $this->db->table($this->tokenTable)
138 ->where('token', '=', $token)
143 * Check if the given token entry has expired.
145 * @param stdClass $tokenEntry
149 protected function entryExpired(stdClass $tokenEntry): bool
151 return Carbon::now()->subHours($this->expiryTime)
152 ->gt(new Carbon($tokenEntry->created_at));