the browser-facing portion of osu!
at master 2.6 kB view raw
1<?php 2 3// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the GNU Affero General Public License v3.0. 4// See the LICENCE file in the repository root for full licence text. 5 6namespace App\Http\Middleware; 7 8use App\Models\OAuth\Token; 9use Closure; 10use Illuminate\Auth\AuthenticationException; 11use Illuminate\Http\Request; 12use Laravel\Passport\Exceptions\MissingScopeException; 13 14class RequireScopes 15{ 16 const NO_TOKEN_REQUIRED = [ 17 'api/v2/changelog/', 18 'api/v2/comments/', 19 'api/v2/news/', 20 'api/v2/seasonal-backgrounds/', 21 'api/v2/wiki/', 22 ]; 23 24 // TODO: this should be definable per-controller or action. 25 public static function noTokenRequired($request) 26 { 27 $path = "{$request->decodedPath()}/"; 28 29 return $request->isMethod('GET') && starts_with($path, static::NO_TOKEN_REQUIRED); 30 } 31 32 public function handle($request, Closure $next, ...$scopes) 33 { 34 if (!is_api_request() || static::noTokenRequired($request)) { 35 return $next($request); 36 } 37 38 $this->validateScopes(oauth_token(), $scopes); 39 40 return $next($request); 41 } 42 43 protected function validateScopes(?Token $token, $scopes) 44 { 45 if ($token === null) { 46 throw new AuthenticationException(); 47 } 48 49 if (!$this->requestHasScopedMiddleware(request())) { 50 if (!$token->can('*')) { 51 throw new MissingScopeException(); 52 } 53 } else { 54 foreach ($scopes as $scope) { 55 if ($scope !== 'any' && !$token->can($scope)) { 56 throw new MissingScopeException([$scope], 'A required scope is missing.'); 57 } 58 } 59 } 60 } 61 62 /** 63 * Returns if the request contains this middleware with scope parameter checks. 64 * 65 * @param Request $request 66 * 67 * @return bool 68 */ 69 private function requestHasScopedMiddleware(Request $request): bool 70 { 71 $value = $request->attributes->get('requestHasScopedMiddleware'); 72 if ($value === null) { 73 $value = $this->containsScoped($request); 74 $request->attributes->set('requestHasScopedMiddleware', $value); 75 } 76 77 return $value; 78 } 79 80 private function containsScoped(Request $request) 81 { 82 foreach ($request->route()->gatherMiddleware() as $middleware) { 83 if (is_string($middleware) && starts_with($middleware, 'require-scopes:')) { 84 return true; 85 } 86 } 87 88 return false; 89 } 90}