From e023acfd00352da37c556ca1472ba0e2a249c0bb Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 16 Nov 2023 17:57:13 +0100 Subject: [PATCH 1/8] Remove unnecessary proptype discrepancy --- .../glitch/features/compose/components/compose_form.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx b/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx index e3ed207043..72fc4c4ab8 100644 --- a/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx @@ -41,7 +41,7 @@ const messages = defineMessages({ class ComposeForm extends ImmutablePureComponent { static propTypes = { intl: PropTypes.object.isRequired, - text: PropTypes.string, + text: PropTypes.string.isRequired, suggestions: ImmutablePropTypes.list, spoiler: PropTypes.bool, privacy: PropTypes.string, From d3ae5b21d2b26be7a35f635361d83969156a2aee Mon Sep 17 00:00:00 2001 From: Claire Date: Thu, 16 Nov 2023 18:02:01 +0100 Subject: [PATCH 2/8] Reduce code and markup discrepancies on reply indicator --- .../compose/components/reply_indicator.jsx | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx index 941a789328..661dff3d54 100644 --- a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx @@ -6,8 +6,9 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import AttachmentList from 'flavours/glitch/components/attachment_list'; -import { IconButton } from 'flavours/glitch/components/icon_button'; -import AccountContainer from 'flavours/glitch/containers/account_container'; + +import { IconButton } from '../../../components/icon_button'; +import AccountContainer from '../../../containers/account_container'; const messages = defineMessages({ cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' }, @@ -17,8 +18,8 @@ class ReplyIndicator extends ImmutablePureComponent { static propTypes = { status: ImmutablePropTypes.map, - intl: PropTypes.object.isRequired, onCancel: PropTypes.func, + intl: PropTypes.object.isRequired, }; handleClick = () => { @@ -35,38 +36,32 @@ class ReplyIndicator extends ImmutablePureComponent { return null; } + const content = { __html: status.get('contentHtml') }; + const account = status.get('account'); - const content = status.get('content'); - const attachments = status.get('media_attachments'); return ( -
-
- +
+
+
+ {account && ( )} -
-
- {attachments.size > 0 && ( +
+ +
+ + {status.get('media_attachments').size > 0 && ( )} -
+ ); } From d59196e1701b91267176b243d16ccc7d08206ae5 Mon Sep 17 00:00:00 2001 From: Claire Date: Mon, 20 Nov 2023 13:02:49 +0100 Subject: [PATCH 3/8] Change glitch-soc's CSP config to match upstream's closer (#2474) --- .../initializers/content_security_policy.rb | 72 +++++++++---------- spec/requests/content_security_policy_spec.rb | 2 +- 2 files changed, 35 insertions(+), 39 deletions(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 9b83fd342c..7686c4727c 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -14,6 +14,17 @@ def host_to_url(str) uri.to_s end +base_host = Rails.configuration.x.web_domain + +assets_host = Rails.configuration.action_controller.asset_host +assets_host ||= host_to_url(base_host) + +media_host = host_to_url(ENV['S3_ALIAS_HOST']) +media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST']) +media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST']) +media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true' +media_host ||= assets_host + def sso_host return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' return unless ENV['OMNIAUTH_ONLY'] == 'true' @@ -32,50 +43,35 @@ def sso_host end end -unless Rails.env.development? - assets_host = Rails.configuration.action_controller.asset_host || "https://#{ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']}" - data_hosts = [assets_host] +Rails.application.config.content_security_policy do |p| + p.base_uri :none + p.default_src :none + p.frame_ancestors :none + p.font_src :self, assets_host + p.img_src :self, :data, :blob, assets_host + p.style_src :self, assets_host + p.media_src :self, :data, assets_host + p.frame_src :self, :https + p.manifest_src :self, assets_host - if ENV['S3_ENABLED'] == 'true' || ENV['AZURE_ENABLED'] == 'true' - attachments_host = host_to_url(ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com") - elsif ENV['SWIFT_ENABLED'] == 'true' - attachments_host = ENV['SWIFT_OBJECT_URL'] - attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}" + if sso_host.present? + p.form_action :self, sso_host else - attachments_host = nil + p.form_action :self end - data_hosts << attachments_host unless attachments_host.nil? + p.child_src :self, :blob, assets_host + p.worker_src :self, :blob, assets_host - if ENV['PAPERCLIP_ROOT_URL'] - url = Addressable::URI.parse(assets_host) + ENV['PAPERCLIP_ROOT_URL'] - data_hosts << "https://#{url.host}" - end + if Rails.env.development? + webpacker_public_host = ENV.fetch('WEBPACKER_DEV_SERVER_PUBLIC', Webpacker.config.dev_server[:public]) + webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" } - data_hosts.concat(ENV['EXTRA_DATA_HOSTS'].split('|')) if ENV['EXTRA_DATA_HOSTS'] - - data_hosts.uniq! - - Rails.application.config.content_security_policy do |p| - p.base_uri :none - p.default_src :none - p.frame_ancestors :none - p.script_src :self, assets_host, "'wasm-unsafe-eval'" - p.font_src :self, assets_host - p.img_src :self, :data, :blob, *data_hosts - p.style_src :self, assets_host - p.media_src :self, :data, *data_hosts - p.frame_src :self, :https - p.child_src :self, :blob, assets_host - p.worker_src :self, :blob, assets_host - p.connect_src :self, :blob, :data, Rails.configuration.x.streaming_api_base_url, *data_hosts - p.manifest_src :self, assets_host - - if sso_host.present? - p.form_action :self, sso_host - else - p.form_action :self - end + p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls + p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host + else + p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url + p.script_src :self, assets_host, "'wasm-unsafe-eval'" end end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index d327ac1b45..787fc9e505 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -20,7 +20,7 @@ describe 'Content-Security-Policy' do "form-action 'self'", "child-src 'self' blob: https://cb6e6126.ngrok.io", "worker-src 'self' blob: https://cb6e6126.ngrok.io", - "connect-src 'self' blob: data: ws://localhost:4000 https://cb6e6126.ngrok.io", + "connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000", "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" ) end From 9ab1aa15e96f6d0f77664cd923cd9e54ce5e1248 Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 19 Nov 2023 21:28:53 +0100 Subject: [PATCH 4/8] Change `ReplyIndicator` implementation and markup to match upstream's --- .../compose/components/reply_indicator.jsx | 31 ++++++++++--------- .../containers/reply_indicator_container.js | 5 ++- .../styles/components/compose_form.scss | 23 +++++++++++--- 3 files changed, 40 insertions(+), 19 deletions(-) diff --git a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx index 661dff3d54..6a8bf6e882 100644 --- a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx @@ -6,9 +6,11 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import AttachmentList from 'flavours/glitch/components/attachment_list'; +import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router'; +import { Avatar } from '../../../components/avatar'; +import { DisplayName } from '../../../components/display_name'; import { IconButton } from '../../../components/icon_button'; -import AccountContainer from '../../../containers/account_container'; const messages = defineMessages({ cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' }, @@ -18,14 +20,19 @@ class ReplyIndicator extends ImmutablePureComponent { static propTypes = { status: ImmutablePropTypes.map, - onCancel: PropTypes.func, + onCancel: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, + ...WithOptionalRouterPropTypes, }; handleClick = () => { - const { onCancel } = this.props; - if (onCancel) { - onCancel(); + this.props.onCancel(); + }; + + handleAccountClick = (e) => { + if (e.button === 0 && !(e.ctrlKey || e.metaKey)) { + e.preventDefault(); + this.props.history?.push(`/@${this.props.status.getIn(['account', 'acct'])}`); } }; @@ -38,19 +45,15 @@ class ReplyIndicator extends ImmutablePureComponent { const content = { __html: status.get('contentHtml') }; - const account = status.get('account'); - return (
- {account && ( - - )} + +
+ +
@@ -67,4 +70,4 @@ class ReplyIndicator extends ImmutablePureComponent { } -export default injectIntl(ReplyIndicator); +export default withOptionalRouter(injectIntl(ReplyIndicator)); diff --git a/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js b/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js index 678124b2a8..1147e448af 100644 --- a/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js +++ b/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js @@ -1,9 +1,12 @@ import { connect } from 'react-redux'; import { cancelReplyCompose } from '../../../actions/compose'; +import { makeGetStatus } from '../../../selectors'; import ReplyIndicator from '../components/reply_indicator'; const makeMapStateToProps = () => { + const getStatus = makeGetStatus(); + const mapStateToProps = state => { let statusId = state.getIn(['compose', 'id'], null); let editing = true; @@ -14,7 +17,7 @@ const makeMapStateToProps = () => { } return { - status: state.getIn(['statuses', statusId]), + status: getStatus(state, { id: statusId }), editing, }; }; diff --git a/app/javascript/flavours/glitch/styles/components/compose_form.scss b/app/javascript/flavours/glitch/styles/components/compose_form.scss index 0f64c0dcc1..d84e672b8f 100644 --- a/app/javascript/flavours/glitch/styles/components/compose_form.scss +++ b/app/javascript/flavours/glitch/styles/components/compose_form.scss @@ -141,10 +141,6 @@ .reply-indicator__header { margin-bottom: 5px; overflow: hidden; - - & > .account.small { - color: $inverted-text-color; - } } .reply-indicator__cancel { @@ -152,6 +148,25 @@ line-height: 24px; } +.reply-indicator__display-name { + color: $inverted-text-color; + display: block; + max-width: 100%; + line-height: 24px; + overflow: hidden; + text-decoration: none; + + & > .display-name { + line-height: unset; + height: unset; + } +} + +.reply-indicator__display-avatar { + float: left; + margin-inline-end: 5px; +} + .reply-indicator__content { position: relative; font-size: 14px; From f00fcda785b2a107467190d24a1ac0c2565ac2bc Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 19 Nov 2023 22:04:48 +0100 Subject: [PATCH 5/8] Reduce differences with upstream in `Account` component --- .../flavours/glitch/components/account.jsx | 36 +++---------------- .../glitch/styles/components/accounts.scss | 15 -------- 2 files changed, 4 insertions(+), 47 deletions(-) diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx index 8aaafc18b9..78cf59e345 100644 --- a/app/javascript/flavours/glitch/components/account.jsx +++ b/app/javascript/flavours/glitch/components/account.jsx @@ -18,7 +18,7 @@ import { RelativeTimestamp } from './relative_timestamp'; const messages = defineMessages({ follow: { id: 'account.follow', defaultMessage: 'Follow' }, unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' }, - requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' }, + requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' }, mute_notifications: { id: 'account.mute_notifications', defaultMessage: 'Mute notifications from @{name}' }, @@ -38,7 +38,6 @@ class Account extends ImmutablePureComponent { onMuteNotifications: PropTypes.func.isRequired, intl: PropTypes.object.isRequired, hidden: PropTypes.bool, - small: PropTypes.bool, actionIcon: PropTypes.string, actionTitle: PropTypes.string, defaultAction: PropTypes.string, @@ -74,17 +73,7 @@ class Account extends ImmutablePureComponent { }; render () { - const { - account, - hidden, - intl, - small, - onActionClick, - actionIcon, - actionTitle, - defaultAction, - size, - } = this.props; + const { account, intl, hidden, onActionClick, actionIcon, actionTitle, defaultAction, size } = this.props; if (!account) { return ( @@ -114,7 +103,7 @@ class Account extends ImmutablePureComponent { if (actionIcon) { buttons = ; } - } else if (account.get('id') !== me && !small && account.get('relationship', null) !== null) { + } else if (account.get('id') !== me && account.get('relationship', null) !== null) { const following = account.getIn(['relationship', 'following']); const requested = account.getIn(['relationship', 'requested']); const blocking = account.getIn(['relationship', 'blocking']); @@ -151,24 +140,7 @@ class Account extends ImmutablePureComponent { mute_expires_at =
; } - return small ? ( - -
- -
- -
- ) : ( + return (
diff --git a/app/javascript/flavours/glitch/styles/components/accounts.scss b/app/javascript/flavours/glitch/styles/components/accounts.scss index e68c6cac04..5d4426fbc6 100644 --- a/app/javascript/flavours/glitch/styles/components/accounts.scss +++ b/app/javascript/flavours/glitch/styles/components/accounts.scss @@ -27,21 +27,6 @@ -webkit-box-orient: vertical; color: $ui-secondary-color; } - - &.small { - border: 0; - padding: 0; - - & > .account__avatar-wrapper { - margin: 0; - margin-inline-end: 8px; - } - - & > .display-name { - height: 24px; - line-height: 24px; - } - } } .follow-recommendations-account { From 6cfa0245ca9360abd6abf2aef339999613e75d9e Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 21 Nov 2023 13:45:29 +0100 Subject: [PATCH 6/8] Fix image and media loading when using external storage server Fixes #2479 --- config/initializers/content_security_policy.rb | 4 ++-- spec/requests/content_security_policy_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 7686c4727c..a40763fbe5 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -48,9 +48,9 @@ Rails.application.config.content_security_policy do |p| p.default_src :none p.frame_ancestors :none p.font_src :self, assets_host - p.img_src :self, :data, :blob, assets_host + p.img_src :self, :data, :blob, assets_host, media_host p.style_src :self, assets_host - p.media_src :self, :data, assets_host + p.media_src :self, :data, assets_host, media_host p.frame_src :self, :https p.manifest_src :self, assets_host diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index 787fc9e505..efd0b9d3cc 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -12,9 +12,9 @@ describe 'Content-Security-Policy' do "default-src 'none'", "frame-ancestors 'none'", "font-src 'self' https://cb6e6126.ngrok.io", - "img-src 'self' data: blob: https://cb6e6126.ngrok.io", + "img-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io", "style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='", - "media-src 'self' data: https://cb6e6126.ngrok.io", + "media-src 'self' data: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io", "frame-src 'self' https:", "manifest-src 'self' https://cb6e6126.ngrok.io", "form-action 'self'", From b3581d1e2f8403a6d9d00f2f4b77bf107d40b97c Mon Sep 17 00:00:00 2001 From: Jeong Arm Date: Sat, 25 Nov 2023 01:40:31 +0900 Subject: [PATCH 7/8] Fix @rails/ujs import on public.jsx (#2482) Related: 8a131fb7bc3 --- app/javascript/packs/public.jsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/javascript/packs/public.jsx b/app/javascript/packs/public.jsx index 62ab7b4282..3831137762 100644 --- a/app/javascript/packs/public.jsx +++ b/app/javascript/packs/public.jsx @@ -5,7 +5,7 @@ import { createRoot } from 'react-dom/client'; import { IntlMessageFormat } from 'intl-messageformat'; import { defineMessages } from 'react-intl'; -import delegate from '@rails/ujs'; +import Rails from '@rails/ujs'; import axios from 'axios'; import { throttle } from 'lodash'; @@ -129,7 +129,7 @@ function loaded() { }); } - delegate(document, '#user_account_attributes_username', 'input', throttle(({ target }) => { + Rails.delegate(document, '#user_account_attributes_username', 'input', throttle(({ target }) => { if (target.value && target.value.length > 0) { axios.get('/api/v1/accounts/lookup', { params: { acct: target.value } }).then(() => { target.setCustomValidity(formatMessage(messages.usernameTaken)); @@ -141,7 +141,7 @@ function loaded() { } }, 500, { leading: false, trailing: true })); - delegate(document, '#user_password,#user_password_confirmation', 'input', () => { + Rails.delegate(document, '#user_password,#user_password_confirmation', 'input', () => { const password = document.getElementById('user_password'); const confirmation = document.getElementById('user_password_confirmation'); if (!confirmation) return; @@ -155,7 +155,7 @@ function loaded() { } }); - delegate(document, '.status__content__spoiler-link', 'click', function() { + Rails.delegate(document, '.status__content__spoiler-link', 'click', function() { const statusEl = this.parentNode.parentNode; if (statusEl.dataset.spoiler === 'expanded') { @@ -192,23 +192,23 @@ const toggleSidebar = () => { sidebar.classList.toggle('visible'); }; -delegate(document, '.sidebar__toggle__icon', 'click', () => { +Rails.delegate(document, '.sidebar__toggle__icon', 'click', () => { toggleSidebar(); }); -delegate(document, '.sidebar__toggle__icon', 'keydown', e => { +Rails.delegate(document, '.sidebar__toggle__icon', 'keydown', e => { if (e.key === ' ' || e.key === 'Enter') { e.preventDefault(); toggleSidebar(); } }); -delegate(document, '.custom-emoji', 'mouseover', ({ target }) => target.src = target.getAttribute('data-original')); -delegate(document, '.custom-emoji', 'mouseout', ({ target }) => target.src = target.getAttribute('data-static')); +Rails.delegate(document, '.custom-emoji', 'mouseover', ({ target }) => target.src = target.getAttribute('data-original')); +Rails.delegate(document, '.custom-emoji', 'mouseout', ({ target }) => target.src = target.getAttribute('data-static')); // Empty the honeypot fields in JS in case something like an extension // automatically filled them. -delegate(document, '#registration_new_user,#new_user', 'submit', () => { +Rails.delegate(document, '#registration_new_user,#new_user', 'submit', () => { ['user_website', 'user_confirm_password', 'registration_user_website', 'registration_user_confirm_password'].forEach(id => { const field = document.getElementById(id); if (field) { From 660372d13069658f79da6fdf6b7f0e3e95dd7724 Mon Sep 17 00:00:00 2001 From: Claire Date: Sun, 26 Nov 2023 15:32:35 +0100 Subject: [PATCH 8/8] Revert recent CSP changes (#2485) * Revert "Fix image and media loading when using external storage server" This reverts commit 6cfa0245ca9360abd6abf2aef339999613e75d9e. * Revert "Change glitch-soc's CSP config to match upstream's closer (#2474)" This reverts commit d59196e1701b91267176b243d16ccc7d08206ae5. --- .../initializers/content_security_policy.rb | 72 ++++++++++--------- spec/requests/content_security_policy_spec.rb | 6 +- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index a40763fbe5..9b83fd342c 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -14,17 +14,6 @@ def host_to_url(str) uri.to_s end -base_host = Rails.configuration.x.web_domain - -assets_host = Rails.configuration.action_controller.asset_host -assets_host ||= host_to_url(base_host) - -media_host = host_to_url(ENV['S3_ALIAS_HOST']) -media_host ||= host_to_url(ENV['S3_CLOUDFRONT_HOST']) -media_host ||= host_to_url(ENV['AZURE_ALIAS_HOST']) -media_host ||= host_to_url(ENV['S3_HOSTNAME']) if ENV['S3_ENABLED'] == 'true' -media_host ||= assets_host - def sso_host return unless ENV['ONE_CLICK_SSO_LOGIN'] == 'true' return unless ENV['OMNIAUTH_ONLY'] == 'true' @@ -43,35 +32,50 @@ def sso_host end end -Rails.application.config.content_security_policy do |p| - p.base_uri :none - p.default_src :none - p.frame_ancestors :none - p.font_src :self, assets_host - p.img_src :self, :data, :blob, assets_host, media_host - p.style_src :self, assets_host - p.media_src :self, :data, assets_host, media_host - p.frame_src :self, :https - p.manifest_src :self, assets_host +unless Rails.env.development? + assets_host = Rails.configuration.action_controller.asset_host || "https://#{ENV['WEB_DOMAIN'] || ENV['LOCAL_DOMAIN']}" + data_hosts = [assets_host] - if sso_host.present? - p.form_action :self, sso_host + if ENV['S3_ENABLED'] == 'true' || ENV['AZURE_ENABLED'] == 'true' + attachments_host = host_to_url(ENV['S3_ALIAS_HOST'] || ENV['S3_CLOUDFRONT_HOST'] || ENV['AZURE_ALIAS_HOST'] || ENV['S3_HOSTNAME'] || "s3-#{ENV['S3_REGION'] || 'us-east-1'}.amazonaws.com") + elsif ENV['SWIFT_ENABLED'] == 'true' + attachments_host = ENV['SWIFT_OBJECT_URL'] + attachments_host = "https://#{Addressable::URI.parse(attachments_host).host}" else - p.form_action :self + attachments_host = nil end - p.child_src :self, :blob, assets_host - p.worker_src :self, :blob, assets_host + data_hosts << attachments_host unless attachments_host.nil? - if Rails.env.development? - webpacker_public_host = ENV.fetch('WEBPACKER_DEV_SERVER_PUBLIC', Webpacker.config.dev_server[:public]) - webpacker_urls = %w(ws http).map { |protocol| "#{protocol}#{Webpacker.dev_server.https? ? 's' : ''}://#{webpacker_public_host}" } + if ENV['PAPERCLIP_ROOT_URL'] + url = Addressable::URI.parse(assets_host) + ENV['PAPERCLIP_ROOT_URL'] + data_hosts << "https://#{url.host}" + end - p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url, *webpacker_urls - p.script_src :self, :unsafe_inline, :unsafe_eval, assets_host - else - p.connect_src :self, :data, :blob, assets_host, media_host, Rails.configuration.x.streaming_api_base_url - p.script_src :self, assets_host, "'wasm-unsafe-eval'" + data_hosts.concat(ENV['EXTRA_DATA_HOSTS'].split('|')) if ENV['EXTRA_DATA_HOSTS'] + + data_hosts.uniq! + + Rails.application.config.content_security_policy do |p| + p.base_uri :none + p.default_src :none + p.frame_ancestors :none + p.script_src :self, assets_host, "'wasm-unsafe-eval'" + p.font_src :self, assets_host + p.img_src :self, :data, :blob, *data_hosts + p.style_src :self, assets_host + p.media_src :self, :data, *data_hosts + p.frame_src :self, :https + p.child_src :self, :blob, assets_host + p.worker_src :self, :blob, assets_host + p.connect_src :self, :blob, :data, Rails.configuration.x.streaming_api_base_url, *data_hosts + p.manifest_src :self, assets_host + + if sso_host.present? + p.form_action :self, sso_host + else + p.form_action :self + end end end diff --git a/spec/requests/content_security_policy_spec.rb b/spec/requests/content_security_policy_spec.rb index efd0b9d3cc..d327ac1b45 100644 --- a/spec/requests/content_security_policy_spec.rb +++ b/spec/requests/content_security_policy_spec.rb @@ -12,15 +12,15 @@ describe 'Content-Security-Policy' do "default-src 'none'", "frame-ancestors 'none'", "font-src 'self' https://cb6e6126.ngrok.io", - "img-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io", + "img-src 'self' data: blob: https://cb6e6126.ngrok.io", "style-src 'self' https://cb6e6126.ngrok.io 'nonce-ZbA+JmE7+bK8F5qvADZHuQ=='", - "media-src 'self' data: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io", + "media-src 'self' data: https://cb6e6126.ngrok.io", "frame-src 'self' https:", "manifest-src 'self' https://cb6e6126.ngrok.io", "form-action 'self'", "child-src 'self' blob: https://cb6e6126.ngrok.io", "worker-src 'self' blob: https://cb6e6126.ngrok.io", - "connect-src 'self' data: blob: https://cb6e6126.ngrok.io https://cb6e6126.ngrok.io ws://localhost:4000", + "connect-src 'self' blob: data: ws://localhost:4000 https://cb6e6126.ngrok.io", "script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'" ) end