| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Auth\Access; | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | use BookStack\Auth\User; | 
					
						
							|  |  |  | use BookStack\Exceptions\UserTokenExpiredException; | 
					
						
							|  |  |  | use BookStack\Exceptions\UserTokenNotFoundException; | 
					
						
							|  |  |  | use Carbon\Carbon; | 
					
						
							| 
									
										
										
										
											2021-09-01 04:50:23 +08:00
										 |  |  | 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. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @var string | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $tokenTable = 'user_tokens'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Token expiry time in hours. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @var int | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected $expiryTime = 24; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Delete all email confirmations that belong to a user. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param User $user | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function deleteByUser(User $user) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-09-01 04:50:23 +08:00
										 |  |  |         return DB::table($this->tokenTable) | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |             ->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 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param string $token | 
					
						
							| 
									
										
										
										
											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
										 |  |  |      * | 
					
						
							|  |  |  |      * @return int | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											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)) { | 
					
						
							| 
									
										
										
										
											2019-08-18 20:55:28 +08:00
										 |  |  |             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
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											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
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param User $user | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return string | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											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(); | 
					
						
							| 
									
										
										
										
											2021-09-01 04:50:23 +08:00
										 |  |  |         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
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param string $token | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |     protected function tokenExists(string $token): bool | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-09-01 04:50:23 +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. | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param string $token | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return object|null | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function getEntryByToken(string $token) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2021-09-01 04:50:23 +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
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @param stdClass $tokenEntry | 
					
						
							| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  |      * | 
					
						
							| 
									
										
										
										
											2019-08-17 22:52:33 +08:00
										 |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											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)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-09-16 01:29:51 +08:00
										 |  |  | } |