diff --git a/app/Attributes/DisabledInDemo.php b/app/Attributes/DisabledInDemo.php new file mode 100644 index 00000000..3551ff1a --- /dev/null +++ b/app/Attributes/DisabledInDemo.php @@ -0,0 +1,14 @@ +trySendResetPasswordLink($request->email) ? response()->noContent() : response('', Response::HTTP_NOT_FOUND); diff --git a/app/Http/Controllers/API/Podcast/PodcastController.php b/app/Http/Controllers/API/Podcast/PodcastController.php index 174acf17..834fe1e9 100644 --- a/app/Http/Controllers/API/Podcast/PodcastController.php +++ b/app/Http/Controllers/API/Podcast/PodcastController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\API\Podcast; +use App\Attributes\DisabledInDemo; use App\Exceptions\UserAlreadySubscribedToPodcast; use App\Http\Controllers\Controller; use App\Http\Requests\API\Podcast\PodcastStoreRequest; @@ -29,10 +30,9 @@ class PodcastController extends Controller return PodcastResourceCollection::make($this->podcastRepository->getAllByUser($this->user)); } + #[DisabledInDemo] public function store(PodcastStoreRequest $request) { - self::disableInDemo(); - try { return PodcastResource::make($this->podcastService->addPodcast($request->url, $this->user)); } catch (UserAlreadySubscribedToPodcast) { diff --git a/app/Http/Controllers/API/ProfileController.php b/app/Http/Controllers/API/ProfileController.php index d26e97ae..f0e0b6e4 100644 --- a/app/Http/Controllers/API/ProfileController.php +++ b/app/Http/Controllers/API/ProfileController.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers\API; +use App\Attributes\DisabledInDemo; use App\Http\Controllers\Controller; use App\Http\Requests\API\ProfileUpdateRequest; use App\Http\Resources\UserResource; @@ -30,10 +31,9 @@ class ProfileController extends Controller return UserResource::make($this->user); } + #[DisabledInDemo(Response::HTTP_NO_CONTENT)] public function update(ProfileUpdateRequest $request) { - static::disableInDemo(Response::HTTP_NO_CONTENT); - // If the user is not using SSO, we need to verify their current password. throw_if( !$this->user->is_sso && !$this->hash->check($request->current_password, $this->user->password), diff --git a/app/Http/Controllers/API/ResetPasswordController.php b/app/Http/Controllers/API/ResetPasswordController.php index 834e9d36..dd3de874 100644 --- a/app/Http/Controllers/API/ResetPasswordController.php +++ b/app/Http/Controllers/API/ResetPasswordController.php @@ -2,17 +2,17 @@ namespace App\Http\Controllers\API; +use App\Attributes\DisabledInDemo; use App\Http\Controllers\Controller; use App\Http\Requests\API\ResetPasswordRequest; use App\Services\AuthenticationService; use Illuminate\Http\Response; +#[DisabledInDemo] class ResetPasswordController extends Controller { public function __invoke(ResetPasswordRequest $request, AuthenticationService $auth) { - static::disableInDemo(); - return $auth->tryResetPasswordUsingBroker($request->email, $request->password, $request->token) ? response()->noContent() : response('', Response::HTTP_UNPROCESSABLE_ENTITY); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 98733dd6..345847e2 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -5,7 +5,6 @@ namespace App\Http\Controllers; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; -use Illuminate\Http\Response; use Illuminate\Routing\Controller as BaseController; abstract class Controller extends BaseController @@ -13,9 +12,4 @@ abstract class Controller extends BaseController use AuthorizesRequests; use DispatchesJobs; use ValidatesRequests; - - protected static function disableInDemo(int $code = Response::HTTP_FORBIDDEN): void - { - abort_if(config('koel.misc.demo'), $code); - } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index e18eb837..ce585213 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -6,6 +6,7 @@ use App\Http\Middleware\AudioAuthenticate; use App\Http\Middleware\Authenticate; use App\Http\Middleware\EncryptCookies; use App\Http\Middleware\ForceHttps; +use App\Http\Middleware\HandleDemoMode; use App\Http\Middleware\ObjectStorageAuthenticate; use App\Http\Middleware\ThrottleRequests; use App\Http\Middleware\TrimStrings; @@ -48,10 +49,12 @@ class Kernel extends HttpKernel StartSession::class, VerifyCsrfToken::class, SubstituteBindings::class, + HandleDemoMode::class, ], 'api' => [ 'throttle:60,1', SubstituteBindings::class, + HandleDemoMode::class, ], ]; diff --git a/app/Http/Middleware/HandleDemoMode.php b/app/Http/Middleware/HandleDemoMode.php new file mode 100644 index 00000000..5c5c97c0 --- /dev/null +++ b/app/Http/Middleware/HandleDemoMode.php @@ -0,0 +1,44 @@ +route(); + $class = $route->getControllerClass(); + $method = $route->getActionMethod(); + + $controllerReflection = new ReflectionClass($class); + + foreach ($controllerReflection->getAttributes(DisabledInDemo::class) as $attribute) { + abort($attribute->newInstance()->code); + } + + $methodReflection = new ReflectionMethod($class, $method); + + foreach ($methodReflection->getAttributes(DisabledInDemo::class) as $attribute) { + abort($attribute->newInstance()->code); + } + } + + /** + * @param Closure(Request): Response $next + */ + public function handle(Request $request, Closure $next): Response + { + if (config('koel.misc.demo')) { + self::ensureRequestIsAllowedInDemoMode($request); + } + + return $next($request); + } +} diff --git a/tests/Feature/ForgotPasswordTest.php b/tests/Feature/ForgotPasswordTest.php index 3e4e804f..7730fd80 100644 --- a/tests/Feature/ForgotPasswordTest.php +++ b/tests/Feature/ForgotPasswordTest.php @@ -69,4 +69,25 @@ class ForgotPasswordTest extends TestCase self::assertTrue(Hash::check('old-password', $user->refresh()->password)); Event::assertNotDispatched(PasswordReset::class); } + + #[Test] + public function disabledInDemo(): void + { + config(['koel.misc.demo' => true]); + + $user = create_user(); + + $this->post('/api/reset-password', [ + 'email' => $user->email, + 'password' => 'new-password', + 'token' => Password::createToken($user), + ])->assertForbidden(); + } + + public function tearDown(): void + { + config(['koel.misc.demo' => false]); + + parent::tearDown(); + } } diff --git a/tests/Feature/ProfileTest.php b/tests/Feature/ProfileTest.php index a05b5a9f..7beb4d1d 100644 --- a/tests/Feature/ProfileTest.php +++ b/tests/Feature/ProfileTest.php @@ -101,4 +101,18 @@ class ProfileTest extends TestCase self::assertNull($user->getRawOriginal('avatar')); } + + #[Test] + public function disabledInDemo(): void + { + config(['koel.misc.demo' => true]); + $user = create_user(['password' => Hash::make('secret')]); + + $this->putAs('api/me', [ + 'name' => 'Foo', + 'email' => 'bar@baz.com', + 'current_password' => 'secret', + ], $user) + ->assertNoContent(); + } }