]> BookStack Code Mirror - bookstack/blobdiff - app/Api/ApiTokenGuard.php
Implement the renderPages parameter
[bookstack] / app / Api / ApiTokenGuard.php
index b347e536acb67e230e803065e271daaafb5a209a..e0a50ebe3d2a03f7e90a8b4362ff15283bb73849 100644 (file)
@@ -6,6 +6,7 @@ use BookStack\Exceptions\ApiAuthException;
 use Illuminate\Auth\GuardHelpers;
 use Illuminate\Contracts\Auth\Authenticatable;
 use Illuminate\Contracts\Auth\Guard;
+use Illuminate\Support\Carbon;
 use Illuminate\Support\Facades\Hash;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -33,8 +34,7 @@ class ApiTokenGuard implements Guard
     {
         $this->request = $request;
     }
-
-
+    
     /**
      * @inheritDoc
      */
@@ -84,6 +84,24 @@ class ApiTokenGuard implements Guard
     protected function getAuthorisedUserFromRequest(): Authenticatable
     {
         $authToken = trim($this->request->headers->get('Authorization', ''));
+        $this->validateTokenHeaderValue($authToken);
+
+        [$id, $secret] = explode(':', str_replace('Token ', '', $authToken));
+        $token = ApiToken::query()
+            ->where('token_id', '=', $id)
+            ->with(['user'])->first();
+
+        $this->validateToken($token, $secret);
+
+        return $token->user;
+    }
+
+    /**
+     * Validate the format of the token header value string.
+     * @throws ApiAuthException
+     */
+    protected function validateTokenHeaderValue(string $authToken): void
+    {
         if (empty($authToken)) {
             throw new ApiAuthException(trans('errors.api_no_authorization_found'));
         }
@@ -91,12 +109,15 @@ class ApiTokenGuard implements Guard
         if (strpos($authToken, ':') === false || strpos($authToken, 'Token ') !== 0) {
             throw new ApiAuthException(trans('errors.api_bad_authorization_format'));
         }
+    }
 
-        [$id, $secret] = explode(':', str_replace('Token ', '', $authToken));
-        $token = ApiToken::query()
-            ->where('token_id', '=', $id)
-            ->with(['user'])->first();
-
+    /**
+     * Validate the given secret against the given token and ensure the token
+     * currently has access to the instance API.
+     * @throws ApiAuthException
+     */
+    protected function validateToken(?ApiToken $token, string $secret): void
+    {
         if ($token === null) {
             throw new ApiAuthException(trans('errors.api_user_token_not_found'));
         }
@@ -105,11 +126,14 @@ class ApiTokenGuard implements Guard
             throw new ApiAuthException(trans('errors.api_incorrect_token_secret'));
         }
 
+        $now = Carbon::now();
+        if ($token->expires_at <= $now) {
+            throw new ApiAuthException(trans('errors.api_user_token_expired'), 403);
+        }
+
         if (!$token->user->can('access-api')) {
             throw new ApiAuthException(trans('errors.api_user_no_api_permission'), 403);
         }
-
-        return $token->user;
     }
 
     /**
@@ -132,4 +156,11 @@ class ApiTokenGuard implements Guard
         return Hash::check($credentials['secret'], $token->secret);
     }
 
+    /**
+     * "Log out" the currently authenticated user.
+     */
+    public function logout()
+    {
+        $this->user = null;
+    }
 }
\ No newline at end of file