Add confirmation when redirecting logged-out requests to permalink (#27792)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Eugen Rochko 2024-01-24 11:49:19 +01:00 committed by GitHub
parent 7a1f087659
commit b19ae521b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 165 additions and 29 deletions

View file

@ -21,10 +21,19 @@ module WebAppControllerConcern
def redirect_unauthenticated_to_permalinks! def redirect_unauthenticated_to_permalinks!
return if user_signed_in? && current_account.moved_to_account_id.nil? return if user_signed_in? && current_account.moved_to_account_id.nil?
redirect_path = PermalinkRedirector.new(request.path).redirect_path permalink_redirector = PermalinkRedirector.new(request.path)
return if redirect_path.blank? 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? 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
end end

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -104,3 +104,59 @@
margin-inline-start: 10px; 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;
}
}

View file

@ -5,17 +5,46 @@ class PermalinkRedirector
def initialize(path) def initialize(path)
@path = 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 end
def redirect_path def redirect_path
if at_username_status_request? || statuses_status_request? return ActivityPub::TagManager.instance.url_for(object) if object.present?
find_status_url_by_id(second_segment)
elsif at_username_request? @path.delete_prefix('/deck') if @path.start_with?('/deck')
find_account_url_by_name(first_segment) end
elsif accounts_request? && record_integer_id_request?
find_account_url_by_id(second_segment) def redirect_uri
elsif @path.start_with?('/deck') return ActivityPub::TagManager.instance.uri_for(object) if object.present?
@path.delete_prefix('/deck')
@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
end end
@ -56,22 +85,4 @@ class PermalinkRedirector
def path_segments def path_segments
@path_segments ||= @path.delete_prefix('/deck').delete_prefix('/').split('/') @path_segments ||= @path.delete_prefix('/deck').delete_prefix('/').split('/')
end 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 end

View file

@ -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'

View file

@ -1547,6 +1547,9 @@ en:
errors: errors:
limit_reached: Limit of different reactions reached limit_reached: Limit of different reactions reached
unrecognized_emoji: is not a recognized emoji unrecognized_emoji: is not a recognized emoji
redirects:
prompt: If you trust this link, click it to continue.
title: You are leaving %{instance}.
relationships: relationships:
activity: Account activity activity: Account activity
confirm_follow_selected_followers: Are you sure you want to follow selected followers? confirm_follow_selected_followers: Are you sure you want to follow selected followers?

View file

@ -162,6 +162,11 @@ Rails.application.routes.draw do
end end
end end
namespace :redirect do
resources :accounts, only: :show
resources :statuses, only: :show
end
resources :media, only: [:show] do resources :media, only: [:show] do
get :player get :player
end end