From 2ce99c51dd37ace101ff43a701c51bd7778a3666 Mon Sep 17 00:00:00 2001 From: Tim Rogers Date: Tue, 30 Jul 2024 03:18:00 -0500 Subject: [PATCH] Fixed Rails route covering %40-encoded profile URL paths to not 404 (#31184) --- config/routes.rb | 6 +- spec/routing/accounts_routing_spec.rb | 101 ++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 93bdb95969..3ac619519d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -142,7 +142,11 @@ Rails.application.routes.draw do resource :inbox, only: [:create], module: :activitypub - get '/:encoded_at(*path)', to: redirect('/@%{path}'), constraints: { encoded_at: /%40/ } + constraints(encoded_path: /%40.*/) do + get '/:encoded_path', to: redirect { |params| + "/#{params[:encoded_path].gsub('%40', '@')}" + } + end constraints(username: %r{[^@/.]+}) do with_options to: 'accounts#show' do diff --git a/spec/routing/accounts_routing_spec.rb b/spec/routing/accounts_routing_spec.rb index 8b2c124fd2..588855943e 100644 --- a/spec/routing/accounts_routing_spec.rb +++ b/spec/routing/accounts_routing_spec.rb @@ -47,6 +47,61 @@ describe 'Routes under accounts/' do end end + context 'with local username encoded at' do + include RSpec::Rails::RequestExampleGroup + let(:username) { 'alice' } + + it 'routes /%40:username' do + get "/%40#{username}" + expect(response).to redirect_to("/@#{username}") + end + + it 'routes /%40:username.json' do + get("/%40#{username}.json") + expect(response).to redirect_to("/@#{username}.json") + end + + it 'routes /%40:username.rss' do + get("/%40#{username}.rss") + expect(response).to redirect_to("/@#{username}.rss") + end + + it 'routes /%40:username/:id' do + get("/%40#{username}/123") + expect(response).to redirect_to("/@#{username}/123") + end + + it 'routes /%40:username/:id/embed' do + get("/%40#{username}/123/embed") + expect(response).to redirect_to("/@#{username}/123/embed") + end + + it 'routes /%40:username/following' do + get("/%40#{username}/following") + expect(response).to redirect_to("/@#{username}/following") + end + + it 'routes /%40:username/followers' do + get("/%40#{username}/followers") + expect(response).to redirect_to("/@#{username}/followers") + end + + it 'routes /%40:username/with_replies' do + get("/%40#{username}/with_replies") + expect(response).to redirect_to("/@#{username}/with_replies") + end + + it 'routes /%40:username/media' do + get("/%40#{username}/media") + expect(response).to redirect_to("/@#{username}/media") + end + + it 'routes /%40:username/tagged/:tag' do + get("/%40#{username}/tagged/foo") + expect(response).to redirect_to("/@#{username}/tagged/foo") + end + end + context 'with remote username' do let(:username) { 'alice@example.com' } @@ -82,4 +137,50 @@ describe 'Routes under accounts/' do expect(get("/@#{username}/tagged/foo")).to route_to('home#index', username_with_domain: username, any: 'tagged/foo') end end + + context 'with remote username encoded at' do + include RSpec::Rails::RequestExampleGroup + let(:username) { 'alice%40example.com' } + let(:username_decoded) { 'alice@example.com' } + + it 'routes /%40:username' do + get("/%40#{username}") + expect(response).to redirect_to("/@#{username_decoded}") + end + + it 'routes /%40:username/:id' do + get("/%40#{username}/123") + expect(response).to redirect_to("/@#{username_decoded}/123") + end + + it 'routes /%40:username/:id/embed' do + get("/%40#{username}/123/embed") + expect(response).to redirect_to("/@#{username_decoded}/123/embed") + end + + it 'routes /%40:username/following' do + get("/%40#{username}/following") + expect(response).to redirect_to("/@#{username_decoded}/following") + end + + it 'routes /%40:username/followers' do + get("/%40#{username}/followers") + expect(response).to redirect_to("/@#{username_decoded}/followers") + end + + it 'routes /%40:username/with_replies' do + get("/%40#{username}/with_replies") + expect(response).to redirect_to("/@#{username_decoded}/with_replies") + end + + it 'routes /%40:username/media' do + get("/%40#{username}/media") + expect(response).to redirect_to("/@#{username_decoded}/media") + end + + it 'routes /%40:username/tagged/:tag' do + get("/%40#{username}/tagged/foo") + expect(response).to redirect_to("/@#{username_decoded}/tagged/foo") + end + end end