Skip to content

Commit

Permalink
Add confirmation when redirecting logged-out requests to permalink (m…
Browse files Browse the repository at this point in the history
…astodon#27792)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
  • Loading branch information
Gargron and ClearlyClaire authored Jan 24, 2024
1 parent 7a1f087 commit b19ae52
Show file tree
Hide file tree
Showing 9 changed files with 165 additions and 29 deletions.
15 changes: 12 additions & 3 deletions app/controllers/concerns/web_app_controller_concern.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,19 @@ def set_app_body_class
def redirect_unauthenticated_to_permalinks!
return if user_signed_in? && current_account.moved_to_account_id.nil?

redirect_path = PermalinkRedirector.new(request.path).redirect_path
return if redirect_path.blank?
permalink_redirector = PermalinkRedirector.new(request.path)
return if permalink_redirector.redirect_path.blank?

expires_in(15.seconds, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.day) unless user_signed_in?
redirect_to(redirect_path)

respond_to do |format|
format.html do
redirect_to(permalink_redirector.redirect_confirmation_path, allow_other_host: false)
end

format.json do
redirect_to(permalink_redirector.redirect_uri, allow_other_host: true)
end
end
end
end
10 changes: 10 additions & 0 deletions app/controllers/redirect/accounts_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class Redirect::AccountsController < ApplicationController
private

def set_resource
@resource = Account.find(params[:id])
not_found if @resource.local?
end
end
24 changes: 24 additions & 0 deletions app/controllers/redirect/base_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class Redirect::BaseController < ApplicationController
vary_by 'Accept-Language'

before_action :set_resource
before_action :set_app_body_class

def show
@redirect_path = ActivityPub::TagManager.instance.url_for(@resource)

render 'redirects/show', layout: 'application'
end

private

def set_app_body_class
@body_classes = 'app-body'
end

def set_resource
raise NotImplementedError
end
end
10 changes: 10 additions & 0 deletions app/controllers/redirect/statuses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

class Redirect::StatusesController < Redirect::BaseController
private

def set_resource
@resource = Status.find(params[:id])
not_found if @resource.local? || !@resource.distributable?
end
end
56 changes: 56 additions & 0 deletions app/javascript/styles/mastodon/containers.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,59 @@
margin-inline-start: 10px;
}
}

.redirect {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
font-size: 14px;
line-height: 18px;

&__logo {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 30px;

img {
height: 48px;
}
}

&__message {
text-align: center;

h1 {
font-size: 17px;
line-height: 22px;
font-weight: 700;
margin-bottom: 30px;
}

p {
margin-bottom: 30px;

&:last-child {
margin-bottom: 0;
}
}

a {
color: $highlight-text-color;
font-weight: 500;
text-decoration: none;

&:hover,
&:focus,
&:active {
text-decoration: underline;
}
}
}

&__link {
margin-top: 15px;
}
}
63 changes: 37 additions & 26 deletions app/lib/permalink_redirector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,46 @@ class PermalinkRedirector

def initialize(path)
@path = path
@object = nil
end

def object
@object ||= begin
if at_username_status_request? || statuses_status_request?
status = Status.find_by(id: second_segment)
status if status&.distributable? && !status&.local?
elsif at_username_request?
username, domain = first_segment.delete_prefix('@').split('@')
domain = nil if TagManager.instance.local_domain?(domain)
account = Account.find_remote(username, domain)
account unless account&.local?
elsif accounts_request? && record_integer_id_request?
account = Account.find_by(id: second_segment)
account unless account&.local?
end
end
end

def redirect_path
if at_username_status_request? || statuses_status_request?
find_status_url_by_id(second_segment)
elsif at_username_request?
find_account_url_by_name(first_segment)
elsif accounts_request? && record_integer_id_request?
find_account_url_by_id(second_segment)
elsif @path.start_with?('/deck')
@path.delete_prefix('/deck')
return ActivityPub::TagManager.instance.url_for(object) if object.present?

@path.delete_prefix('/deck') if @path.start_with?('/deck')
end

def redirect_uri
return ActivityPub::TagManager.instance.uri_for(object) if object.present?

@path.delete_prefix('/deck') if @path.start_with?('/deck')
end

def redirect_confirmation_path
case object.class.name
when 'Account'
redirect_account_path(object.id)
when 'Status'
redirect_status_path(object.id)
else
@path.delete_prefix('/deck') if @path.start_with?('/deck')
end
end

Expand Down Expand Up @@ -56,22 +85,4 @@ def second_segment
def path_segments
@path_segments ||= @path.delete_prefix('/deck').delete_prefix('/').split('/')
end

def find_status_url_by_id(id)
status = Status.find_by(id: id)
ActivityPub::TagManager.instance.url_for(status) if status&.distributable? && !status.account.local?
end

def find_account_url_by_id(id)
account = Account.find_by(id: id)
ActivityPub::TagManager.instance.url_for(account) if account.present? && !account.local?
end

def find_account_url_by_name(name)
username, domain = name.gsub(/\A@/, '').split('@')
domain = nil if TagManager.instance.local_domain?(domain)
account = Account.find_remote(username, domain)

ActivityPub::TagManager.instance.url_for(account) if account.present? && !account.local?
end
end
8 changes: 8 additions & 0 deletions app/views/redirects/show.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.redirect
.redirect__logo
= link_to render_logo, root_path

.redirect__message
%h1= t('redirects.title', instance: site_hostname)
%p= t('redirects.prompt')
%p= link_to @redirect_path, @redirect_path, rel: 'noreferrer noopener'
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1547,6 +1547,9 @@ en:
errors:
limit_reached: Limit of different reactions reached
unrecognized_emoji: is not a recognized emoji
redirects:
prompt: If you trust this link, click it to continue.
title: You are leaving %{instance}.
relationships:
activity: Account activity
confirm_follow_selected_followers: Are you sure you want to follow selected followers?
Expand Down
5 changes: 5 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ def redirect_with_vary(path)
end
end

namespace :redirect do
resources :accounts, only: :show
resources :statuses, only: :show
end

resources :media, only: [:show] do
get :player
end
Expand Down

0 comments on commit b19ae52

Please sign in to comment.