From 425311e1d95c8a64ddac6c724fca247b8b893a82 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 9 Dec 2024 23:42:45 +0100 Subject: [PATCH] Change referrer policy to be controlled by header in web UI (#33214) --- .eslintrc.js | 2 +- app/controllers/admin/base_controller.rb | 5 +++++ .../mastodon/components/attachment_list.jsx | 2 +- app/javascript/mastodon/components/dropdown_menu.jsx | 2 +- .../mastodon/components/error_boundary.jsx | 2 +- app/javascript/mastodon/components/follow_button.tsx | 2 +- app/javascript/mastodon/components/media_gallery.jsx | 4 ++-- app/javascript/mastodon/components/server_banner.jsx | 2 +- app/javascript/mastodon/components/status.jsx | 2 +- app/javascript/mastodon/features/about/index.jsx | 2 +- .../mastodon/features/account/components/header.jsx | 2 +- .../mastodon/features/emoji/__tests__/emoji-test.js | 4 ++-- .../getting_started/components/announcements.jsx | 2 +- .../components/relationships_severance_event.jsx | 2 +- .../features/notifications/components/report.jsx | 2 +- .../notifications_v2/components/embedded_status.tsx | 2 +- .../mastodon/features/standalone/status/index.tsx | 2 +- .../mastodon/features/status/components/card.jsx | 6 +++--- .../features/ui/components/actions_modal.jsx | 2 +- .../mastodon/features/ui/components/link_footer.tsx | 12 ++++-------- app/lib/text_formatter.rb | 2 +- app/views/admin/reports/_status.html.haml | 2 +- app/views/admin/reports/actions/preview.html.haml | 2 +- app/views/admin/statuses/show.html.haml | 2 +- app/views/admin/tags/show.html.haml | 4 ++-- app/views/admin/trends/statuses/_status.html.haml | 2 +- app/views/admin/trends/tags/_tag.html.haml | 2 +- app/views/application/_card.html.haml | 2 +- app/views/disputes/strikes/_card.html.haml | 2 +- app/views/filters/statuses/_status_filter.html.haml | 4 ++-- .../oauth/authorized_applications/index.html.haml | 2 +- app/views/redirects/show.html.haml | 2 +- config/environments/production.rb | 2 +- lib/sanitize_ext/sanitize_config.rb | 2 +- spec/lib/sanitize/config_spec.rb | 8 ++++---- 35 files changed, 51 insertions(+), 50 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 93ff1d7b59..480b274fad 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -109,7 +109,7 @@ module.exports = defineConfig({ 'react/jsx-equals-spacing': 'error', 'react/jsx-no-bind': 'error', 'react/jsx-no-useless-fragment': 'error', - 'react/jsx-no-target-blank': 'off', + 'react/jsx-no-target-blank': ['error', { allowReferrer: true }], 'react/jsx-tag-spacing': 'error', 'react/jsx-uses-react': 'off', // not needed with new JSX transform 'react/jsx-wrap-multilines': 'error', diff --git a/app/controllers/admin/base_controller.rb b/app/controllers/admin/base_controller.rb index 48685db17a..3dca3a9614 100644 --- a/app/controllers/admin/base_controller.rb +++ b/app/controllers/admin/base_controller.rb @@ -8,6 +8,7 @@ module Admin layout 'admin' before_action :set_cache_headers + before_action :set_referrer_policy_header after_action :verify_authorized @@ -17,6 +18,10 @@ module Admin response.cache_control.replace(private: true, no_store: true) end + def set_referrer_policy_header + response.headers['Referrer-Policy'] = 'same-origin' + end + def set_user @user = Account.find(params[:account_id]).user || raise(ActiveRecord::RecordNotFound) end diff --git a/app/javascript/mastodon/components/attachment_list.jsx b/app/javascript/mastodon/components/attachment_list.jsx index c5ac046751..f97e22f2d4 100644 --- a/app/javascript/mastodon/components/attachment_list.jsx +++ b/app/javascript/mastodon/components/attachment_list.jsx @@ -36,7 +36,7 @@ export default class AttachmentList extends ImmutablePureComponent { return (
  • - + {compact && } {compact && ' ' } {displayUrl ? filename(displayUrl) : } diff --git a/app/javascript/mastodon/components/dropdown_menu.jsx b/app/javascript/mastodon/components/dropdown_menu.jsx index d731a8e2d1..df0be8bc12 100644 --- a/app/javascript/mastodon/components/dropdown_menu.jsx +++ b/app/javascript/mastodon/components/dropdown_menu.jsx @@ -124,7 +124,7 @@ class DropdownMenu extends PureComponent { return (
  • - + {text}
  • diff --git a/app/javascript/mastodon/components/error_boundary.jsx b/app/javascript/mastodon/components/error_boundary.jsx index 392a3ad61e..ca2f017f3b 100644 --- a/app/javascript/mastodon/components/error_boundary.jsx +++ b/app/javascript/mastodon/components/error_boundary.jsx @@ -98,7 +98,7 @@ export default class ErrorBoundary extends PureComponent { )}

    -

    Mastodon v{version} 路

    +

    Mastodon v{version} 路

    diff --git a/app/javascript/mastodon/components/follow_button.tsx b/app/javascript/mastodon/components/follow_button.tsx index faf9d8bdb8..c62e76d4b5 100644 --- a/app/javascript/mastodon/components/follow_button.tsx +++ b/app/javascript/mastodon/components/follow_button.tsx @@ -88,7 +88,7 @@ export const FollowButton: React.FC<{ {label} diff --git a/app/javascript/mastodon/components/media_gallery.jsx b/app/javascript/mastodon/components/media_gallery.jsx index 59963a0a9f..95b06abc54 100644 --- a/app/javascript/mastodon/components/media_gallery.jsx +++ b/app/javascript/mastodon/components/media_gallery.jsx @@ -106,7 +106,7 @@ class Item extends PureComponent { if (attachment.get('type') === 'unknown') { return (
    - +
    - {domain}, mastodon: Mastodon }} /> + {domain}, mastodon: Mastodon }} />
    diff --git a/app/javascript/mastodon/components/status.jsx b/app/javascript/mastodon/components/status.jsx index cf6fe86c3d..9f57629807 100644 --- a/app/javascript/mastodon/components/status.jsx +++ b/app/javascript/mastodon/components/status.jsx @@ -293,7 +293,7 @@ class Status extends ImmutablePureComponent { if (e?.button === 0 && !(e?.ctrlKey || e?.metaKey)) { history.push(path); } else if (e?.button === 1 || (e?.button === 0 && (e?.ctrlKey || e?.metaKey))) { - window.open(path, '_blank', 'noreferrer noopener'); + window.open(path, '_blank', 'noopener'); } }; diff --git a/app/javascript/mastodon/features/about/index.jsx b/app/javascript/mastodon/features/about/index.jsx index 24141b13cb..34e84506f0 100644 --- a/app/javascript/mastodon/features/about/index.jsx +++ b/app/javascript/mastodon/features/about/index.jsx @@ -123,7 +123,7 @@ class About extends PureComponent {
    `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' />

    {isLoading ? : server.get('domain')}

    -

    Mastodon }} />

    +

    Mastodon }} />

    diff --git a/app/javascript/mastodon/features/account/components/header.jsx b/app/javascript/mastodon/features/account/components/header.jsx index 6583c1f604..fc38adc131 100644 --- a/app/javascript/mastodon/features/account/components/header.jsx +++ b/app/javascript/mastodon/features/account/components/header.jsx @@ -421,7 +421,7 @@ class Header extends ImmutablePureComponent {
    - + diff --git a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js index 9d6ff5226a..022c9baaf7 100644 --- a/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js +++ b/app/javascript/mastodon/features/emoji/__tests__/emoji-test.js @@ -90,8 +90,8 @@ describe('emoji', () => { }); it('keeps ordering as expected (issue fixed by PR 20677)', () => { - expect(emojify('

    馃挄 #foo test: foo.

    ')) - .toEqual('

    馃挄 #foo test: foo.

    '); + expect(emojify('

    馃挄 #foo test: foo.

    ')) + .toEqual('

    馃挄 #foo test: foo.

    '); }); }); }); diff --git a/app/javascript/mastodon/features/getting_started/components/announcements.jsx b/app/javascript/mastodon/features/getting_started/components/announcements.jsx index 3c0b53b9e7..713ad9f069 100644 --- a/app/javascript/mastodon/features/getting_started/components/announcements.jsx +++ b/app/javascript/mastodon/features/getting_started/components/announcements.jsx @@ -85,7 +85,7 @@ class ContentWithRouter extends ImmutablePureComponent { } link.setAttribute('target', '_blank'); - link.setAttribute('rel', 'noopener noreferrer'); + link.setAttribute('rel', 'noopener'); } } diff --git a/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx b/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx index 3075aff31b..65ccd7c276 100644 --- a/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx +++ b/app/javascript/mastodon/features/notifications/components/relationships_severance_event.jsx @@ -28,7 +28,7 @@ export const RelationshipsSeveranceEvent = ({ type, target, followingCount, foll

    {intl.formatMessage(messages[type], { from: {domain}, target: {target}, followingCount, followersCount })}

    - +
    ); diff --git a/app/javascript/mastodon/features/notifications/components/report.jsx b/app/javascript/mastodon/features/notifications/components/report.jsx index 52d6bfee9d..ed043ae789 100644 --- a/app/javascript/mastodon/features/notifications/components/report.jsx +++ b/app/javascript/mastodon/features/notifications/components/report.jsx @@ -55,7 +55,7 @@ class Report extends ImmutablePureComponent {
    - {intl.formatMessage(messages.openReport)} + {intl.formatMessage(messages.openReport)}
    diff --git a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx index ca0d1bc850..88e65c668b 100644 --- a/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx +++ b/app/javascript/mastodon/features/notifications_v2/components/embedded_status.tsx @@ -70,7 +70,7 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({ if (button === 0 && !(ctrlKey || metaKey)) { history.push(path); } else if (button === 1 || (button === 0 && (ctrlKey || metaKey))) { - window.open(path, '_blank', 'noreferrer noopener'); + window.open(path, '_blank', 'noopener'); } } diff --git a/app/javascript/mastodon/features/standalone/status/index.tsx b/app/javascript/mastodon/features/standalone/status/index.tsx index d5cb7e7f40..3b68c5c176 100644 --- a/app/javascript/mastodon/features/standalone/status/index.tsx +++ b/app/javascript/mastodon/features/standalone/status/index.tsx @@ -61,7 +61,7 @@ const Embed: React.FC<{ id: string }> = ({ id }) => { className='embed__overlay' href={permalink} target='_blank' - rel='noreferrer noopener' + rel='noopener' aria-label='' /> diff --git a/app/javascript/mastodon/features/status/components/card.jsx b/app/javascript/mastodon/features/status/components/card.jsx index 136a5568a4..f8d5a26aff 100644 --- a/app/javascript/mastodon/features/status/components/card.jsx +++ b/app/javascript/mastodon/features/status/components/card.jsx @@ -208,7 +208,7 @@ export default class Card extends PureComponent {
    - +
    ) : spoilerButton} @@ -219,7 +219,7 @@ export default class Card extends PureComponent { return (
    {embed} - {description} + {description}
    ); } else if (card.get('image')) { @@ -239,7 +239,7 @@ export default class Card extends PureComponent { return ( <> - + {embed} {description} diff --git a/app/javascript/mastodon/features/ui/components/actions_modal.jsx b/app/javascript/mastodon/features/ui/components/actions_modal.jsx index 4e0879580b..851f828b4e 100644 --- a/app/javascript/mastodon/features/ui/components/actions_modal.jsx +++ b/app/javascript/mastodon/features/ui/components/actions_modal.jsx @@ -24,7 +24,7 @@ export default class ActionsModal extends ImmutablePureComponent { return (
  • - + {icon && }
    {text}
    diff --git a/app/javascript/mastodon/features/ui/components/link_footer.tsx b/app/javascript/mastodon/features/ui/components/link_footer.tsx index 06cb92fe4f..cbfb6a3114 100644 --- a/app/javascript/mastodon/features/ui/components/link_footer.tsx +++ b/app/javascript/mastodon/features/ui/components/link_footer.tsx @@ -26,7 +26,7 @@ export const LinkFooter: React.FC<{ {statusPageUrl && ( <> -
    + @@ -72,15 +72,11 @@ export const LinkFooter: React.FC<{

    Mastodon:{' '} - + - + @@ -91,7 +87,7 @@ export const LinkFooter: React.FC<{ /> - + 'DENY', 'X-Content-Type-Options' => 'nosniff', 'X-XSS-Protection' => '0', - 'Referrer-Policy' => 'same-origin', + 'Referrer-Policy' => ENV['ALLOW_REFERRER_ORIGIN'] == 'true' ? 'origin' : 'same-origin', } # TODO: Remove once devise-two-factor data migration complete diff --git a/lib/sanitize_ext/sanitize_config.rb b/lib/sanitize_ext/sanitize_config.rb index c264548eb5..36c11a8263 100644 --- a/lib/sanitize_ext/sanitize_config.rb +++ b/lib/sanitize_ext/sanitize_config.rb @@ -114,7 +114,7 @@ class Sanitize add_attributes: { 'a' => { - 'rel' => 'nofollow noopener noreferrer', + 'rel' => 'nofollow noopener', 'target' => '_blank', }, }, diff --git a/spec/lib/sanitize/config_spec.rb b/spec/lib/sanitize/config_spec.rb index b1cab85827..b4c849c427 100644 --- a/spec/lib/sanitize/config_spec.rb +++ b/spec/lib/sanitize/config_spec.rb @@ -39,15 +39,15 @@ RSpec.describe Sanitize::Config do end it 'keeps a with href' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' + expect(Sanitize.fragment('Test', subject)).to eq 'Test' end it 'keeps a with translate="no"' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' + expect(Sanitize.fragment('Test', subject)).to eq 'Test' end it 'removes "translate" attribute with invalid value' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' + expect(Sanitize.fragment('Test', subject)).to eq 'Test' end it 'removes a with unparsable href' do @@ -55,7 +55,7 @@ RSpec.describe Sanitize::Config do end it 'keeps a with supported scheme and no host' do - expect(Sanitize.fragment('Test', subject)).to eq 'Test' + expect(Sanitize.fragment('Test', subject)).to eq 'Test' end it 'sanitizes math to LaTeX' do