BookStack/app/Access/UserTokenService.php

113 lines
2.8 KiB
PHP
Raw Normal View History

2021-06-26 23:23:15 +08:00
<?php
2023-05-18 00:56:55 +08:00
namespace BookStack\Access;
2019-08-17 22:52:33 +08:00
use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException;
2023-05-18 00:56:55 +08:00
use BookStack\Users\Models\User;
2019-08-17 22:52:33 +08:00
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
2019-09-14 06:58:40 +08:00
use Illuminate\Support\Str;
2019-08-17 22:52:33 +08:00
use stdClass;
class UserTokenService
{
/**
* Name of table where user tokens are stored.
*/
2023-04-04 17:44:38 +08:00
protected string $tokenTable = 'user_tokens';
2019-08-17 22:52:33 +08:00
/**
* Token expiry time in hours.
*/
2023-04-04 17:44:38 +08:00
protected int $expiryTime = 24;
2019-08-17 22:52:33 +08:00
/**
2023-04-04 17:44:38 +08:00
* Delete all tokens that belong to a user.
2019-08-17 22:52:33 +08:00
*/
2023-04-04 17:44:38 +08:00
public function deleteByUser(User $user): void
2019-08-17 22:52:33 +08:00
{
2023-04-04 17:44:38 +08:00
DB::table($this->tokenTable)
2019-08-17 22:52:33 +08:00
->where('user_id', '=', $user->id)
->delete();
}
/**
2023-04-04 17:44:38 +08:00
* Get the user id from a token, while checking the token exists and has not expired.
2021-06-26 23:23:15 +08:00
*
2019-08-17 22:52:33 +08:00
* @throws UserTokenNotFoundException
* @throws UserTokenExpiredException
*/
2021-06-26 23:23:15 +08:00
public function checkTokenAndGetUserId(string $token): int
2019-08-17 22:52:33 +08:00
{
$entry = $this->getEntryByToken($token);
if (is_null($entry)) {
throw new UserTokenNotFoundException('Token "' . $token . '" not found');
}
if ($this->entryExpired($entry)) {
throw new UserTokenExpiredException("Token of id {$entry->id} has expired.", $entry->user_id);
2019-08-17 22:52:33 +08:00
}
return $entry->user_id;
}
/**
* Creates a unique token within the email confirmation database.
*/
2021-06-26 23:23:15 +08:00
protected function generateToken(): string
2019-08-17 22:52:33 +08:00
{
2019-09-14 06:58:40 +08:00
$token = Str::random(24);
2019-08-17 22:52:33 +08:00
while ($this->tokenExists($token)) {
2019-09-14 06:58:40 +08:00
$token = Str::random(25);
2019-08-17 22:52:33 +08:00
}
2021-06-26 23:23:15 +08:00
2019-08-17 22:52:33 +08:00
return $token;
}
/**
* Generate and store a token for the given user.
*/
2021-06-26 23:23:15 +08:00
protected function createTokenForUser(User $user): string
2019-08-17 22:52:33 +08:00
{
$token = $this->generateToken();
DB::table($this->tokenTable)->insert([
2021-06-26 23:23:15 +08:00
'user_id' => $user->id,
'token' => $token,
2019-08-17 22:52:33 +08:00
'created_at' => Carbon::now(),
2021-06-26 23:23:15 +08:00
'updated_at' => Carbon::now(),
2019-08-17 22:52:33 +08:00
]);
2021-06-26 23:23:15 +08:00
2019-08-17 22:52:33 +08:00
return $token;
}
/**
* Check if the given token exists.
*/
2021-06-26 23:23:15 +08:00
protected function tokenExists(string $token): bool
2019-08-17 22:52:33 +08:00
{
return DB::table($this->tokenTable)
2019-08-17 22:52:33 +08:00
->where('token', '=', $token)->exists();
}
/**
* Get a token entry for the given token.
*/
2023-04-04 17:44:38 +08:00
protected function getEntryByToken(string $token): ?stdClass
2019-08-17 22:52:33 +08:00
{
return DB::table($this->tokenTable)
2019-08-17 22:52:33 +08:00
->where('token', '=', $token)
->first();
}
/**
* Check if the given token entry has expired.
*/
2021-06-26 23:23:15 +08:00
protected function entryExpired(stdClass $tokenEntry): bool
2019-08-17 22:52:33 +08:00
{
return Carbon::now()->subHours($this->expiryTime)
->gt(new Carbon($tokenEntry->created_at));
}
}