BookStack/app/Auth/Access/UserTokenService.php

155 lines
3.4 KiB
PHP
Raw Normal View History

2021-06-26 15:23:15 +00:00
<?php
namespace BookStack\Auth\Access;
2019-08-17 14:52:33 +00:00
use BookStack\Auth\User;
use BookStack\Exceptions\UserTokenExpiredException;
use BookStack\Exceptions\UserTokenNotFoundException;
use Carbon\Carbon;
use Illuminate\Database\Connection as Database;
2019-09-13 22:58:40 +00:00
use Illuminate\Support\Str;
2019-08-17 14:52:33 +00:00
use stdClass;
class UserTokenService
{
/**
* Name of table where user tokens are stored.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @var string
*/
protected $tokenTable = 'user_tokens';
/**
* Token expiry time in hours.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @var int
*/
protected $expiryTime = 24;
protected $db;
/**
* UserTokenService constructor.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param Database $db
*/
public function __construct(Database $db)
{
$this->db = $db;
}
/**
* Delete all email confirmations that belong to a user.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param User $user
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return mixed
*/
public function deleteByUser(User $user)
{
return $this->db->table($this->tokenTable)
->where('user_id', '=', $user->id)
->delete();
}
/**
* Get the user id from a token, while check the token exists and has not expired.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param string $token
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @throws UserTokenNotFoundException
* @throws UserTokenExpiredException
2021-06-26 15:23:15 +00:00
*
* @return int
2019-08-17 14:52:33 +00:00
*/
2021-06-26 15:23:15 +00:00
public function checkTokenAndGetUserId(string $token): int
2019-08-17 14:52:33 +00: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 14:52:33 +00:00
}
return $entry->user_id;
}
/**
* Creates a unique token within the email confirmation database.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return string
*/
2021-06-26 15:23:15 +00:00
protected function generateToken(): string
2019-08-17 14:52:33 +00:00
{
2019-09-13 22:58:40 +00:00
$token = Str::random(24);
2019-08-17 14:52:33 +00:00
while ($this->tokenExists($token)) {
2019-09-13 22:58:40 +00:00
$token = Str::random(25);
2019-08-17 14:52:33 +00:00
}
2021-06-26 15:23:15 +00:00
2019-08-17 14:52:33 +00:00
return $token;
}
/**
* Generate and store a token for the given user.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param User $user
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return string
*/
2021-06-26 15:23:15 +00:00
protected function createTokenForUser(User $user): string
2019-08-17 14:52:33 +00:00
{
$token = $this->generateToken();
$this->db->table($this->tokenTable)->insert([
2021-06-26 15:23:15 +00:00
'user_id' => $user->id,
'token' => $token,
2019-08-17 14:52:33 +00:00
'created_at' => Carbon::now(),
2021-06-26 15:23:15 +00:00
'updated_at' => Carbon::now(),
2019-08-17 14:52:33 +00:00
]);
2021-06-26 15:23:15 +00:00
2019-08-17 14:52:33 +00:00
return $token;
}
/**
* Check if the given token exists.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param string $token
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return bool
*/
2021-06-26 15:23:15 +00:00
protected function tokenExists(string $token): bool
2019-08-17 14:52:33 +00:00
{
return $this->db->table($this->tokenTable)
->where('token', '=', $token)->exists();
}
/**
* Get a token entry for the given token.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param string $token
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return object|null
*/
protected function getEntryByToken(string $token)
{
return $this->db->table($this->tokenTable)
->where('token', '=', $token)
->first();
}
/**
* Check if the given token entry has expired.
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @param stdClass $tokenEntry
2021-06-26 15:23:15 +00:00
*
2019-08-17 14:52:33 +00:00
* @return bool
*/
2021-06-26 15:23:15 +00:00
protected function entryExpired(stdClass $tokenEntry): bool
2019-08-17 14:52:33 +00:00
{
return Carbon::now()->subHours($this->expiryTime)
->gt(new Carbon($tokenEntry->created_at));
}
}