diff --git a/app/Http/Controllers/AuthorizeInteractionController.php b/app/Http/Controllers/AuthorizeInteractionController.php index b0b1d40a8..c5b81cb08 100644 --- a/app/Http/Controllers/AuthorizeInteractionController.php +++ b/app/Http/Controllers/AuthorizeInteractionController.php @@ -20,7 +20,13 @@ class AuthorizeInteractionController extends Controller abort_unless($uri, 404); if (! $request->user()) { - return redirect('/login?next='.urlencode($uri)); + // Store the current Pixelfed URL so Laravel's redirect()->intended() + // returns here after login. The `next` query param was never + // consumed by the login flow, so the remote-follow interaction was + // lost after authenticating. + $request->session()->put('url.intended', $request->fullUrl()); + + return redirect('/login'); } $status = Helpers::statusFetch($uri); diff --git a/tests/Feature/Federation/AuthorizeInteractionRedirectTest.php b/tests/Feature/Federation/AuthorizeInteractionRedirectTest.php new file mode 100644 index 000000000..00ddfa7cd --- /dev/null +++ b/tests/Feature/Federation/AuthorizeInteractionRedirectTest.php @@ -0,0 +1,49 @@ + true]); + // validateUrl resolves the host to a public IP; pre-seed so it passes + // without a real DNS lookup. + Cache::put('helpers:url:public-ips:'.hash('xxh128', 'remote.example'), ['203.0.113.70'], 3600); +}); + +it('redirects a guest to /login and stores the intended interaction url', function () { + $uri = 'https://remote.example/users/alice'; + $target = '/authorize_interaction?'.http_build_query(['uri' => $uri]); + + $response = $this->get($target); + + $response->assertRedirect('/login'); + // Laravel's intended-redirect key holds the full authorize_interaction URL. + expect(session('url.intended'))->toContain('/authorize_interaction'); + expect(session('url.intended'))->toContain('uri='); +}); + +it('redirects to plain /login without the unused next query param', function () { + $uri = 'https://remote.example/users/alice'; + $target = '/authorize_interaction?'.http_build_query(['uri' => $uri]); + + $location = $this->get($target)->headers->get('Location'); + + // The old ?next= param was never consumed; the redirect target is /login + // and the intended URL lives in the session instead. + expect($location)->toEndWith('/login'); + expect($location)->not->toContain('next='); +});