mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-14 00:08:46 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b31a5fc4c | ||
|
|
b6aa0b4990 | ||
|
|
7868b545ed | ||
|
|
bd8d96e699 | ||
|
|
e6591bf322 | ||
|
|
30e25ff7fc | ||
|
|
5ef82d7937 | ||
|
|
e14bf631b5 | ||
|
|
6d46225718 | ||
|
|
022af54ea2 | ||
|
|
bcf788dad7 | ||
|
|
7917b495d2 | ||
|
|
ec2023233d | ||
|
|
e6a6c26c36 | ||
|
|
86a8aa5e5c | ||
|
|
a9f8b1ad96 | ||
|
|
698e4fdef2 | ||
|
|
72b1af137e | ||
|
|
8291afae35 | ||
|
|
1ce0733cac | ||
|
|
8bfbf2abaf |
27
CHANGELOG.md
27
CHANGELOG.md
@@ -2,9 +2,34 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [4.3.8] - 2025-05-06
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
- Update dependencies
|
||||||
|
- Check scheme on account, profile, and media URLs ([GHSA-x2rc-v5wx-g3m5](https://github.com/mastodon/mastodon/security/advisories/GHSA-x2rc-v5wx-g3m5))
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add warning for REDIS_NAMESPACE deprecation at startup (#34581 by @ClearlyClaire)
|
||||||
|
- Add built-in context for interaction policies (#34574 by @ClearlyClaire)
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Change activity distribution error handling to skip retrying for deleted accounts (#33617 by @ClearlyClaire)
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Remove double-query for signed query strings (#34610 by @ClearlyClaire)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix incorrect redirect in response to unauthenticated API requests in limited federation mode (#34549 by @ClearlyClaire)
|
||||||
|
- Fix sign-up e-mail confirmation page reloading on error or redirect (#34548 by @ClearlyClaire)
|
||||||
|
|
||||||
## [4.3.7] - 2025-04-02
|
## [4.3.7] - 2025-04-02
|
||||||
|
|
||||||
### Add
|
### Added
|
||||||
|
|
||||||
- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire)
|
- Add delay to profile updates to debounce them (#34137 by @ClearlyClaire)
|
||||||
- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire)
|
- Add support for paginating partial collections in `SynchronizeFollowersService` (#34272 and #34277 by @ClearlyClaire)
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ GEM
|
|||||||
activerecord (>= 5.a)
|
activerecord (>= 5.a)
|
||||||
database_cleaner-core (~> 2.0.0)
|
database_cleaner-core (~> 2.0.0)
|
||||||
database_cleaner-core (2.0.1)
|
database_cleaner-core (2.0.1)
|
||||||
date (3.3.4)
|
date (3.4.1)
|
||||||
debug (1.9.2)
|
debug (1.9.2)
|
||||||
irb (~> 1.10)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.8)
|
reline (>= 0.3.8)
|
||||||
@@ -447,7 +447,7 @@ GEM
|
|||||||
uri
|
uri
|
||||||
net-http-persistent (4.0.2)
|
net-http-persistent (4.0.2)
|
||||||
connection_pool (~> 2.2)
|
connection_pool (~> 2.2)
|
||||||
net-imap (0.4.19)
|
net-imap (0.5.8)
|
||||||
date
|
date
|
||||||
net-protocol
|
net-protocol
|
||||||
net-ldap (0.19.0)
|
net-ldap (0.19.0)
|
||||||
@@ -458,7 +458,7 @@ GEM
|
|||||||
net-smtp (0.5.1)
|
net-smtp (0.5.1)
|
||||||
net-protocol
|
net-protocol
|
||||||
nio4r (2.7.3)
|
nio4r (2.7.3)
|
||||||
nokogiri (1.18.3)
|
nokogiri (1.18.8)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
oj (3.16.6)
|
oj (3.16.6)
|
||||||
|
|||||||
@@ -72,6 +72,13 @@ class Api::BaseController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Redefine `require_functional!` to properly output JSON instead of HTML redirects
|
||||||
|
def require_functional!
|
||||||
|
return if current_user.functional?
|
||||||
|
|
||||||
|
require_user!
|
||||||
|
end
|
||||||
|
|
||||||
def render_empty
|
def render_empty
|
||||||
render json: {}, status: 200
|
render json: {}, status: 200
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -74,7 +74,23 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def require_functional!
|
def require_functional!
|
||||||
redirect_to edit_user_registration_path unless current_user.functional?
|
return if current_user.functional?
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.any do
|
||||||
|
redirect_to edit_user_registration_path
|
||||||
|
end
|
||||||
|
|
||||||
|
format.json do
|
||||||
|
if !current_user.confirmed?
|
||||||
|
render json: { error: 'Your login is missing a confirmed e-mail address' }, status: 403
|
||||||
|
elsif !current_user.approved?
|
||||||
|
render json: { error: 'Your login is currently pending approval' }, status: 403
|
||||||
|
elsif !current_user.functional?
|
||||||
|
render json: { error: 'Your login is currently disabled' }, status: 403
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def skip_csrf_meta_tags?
|
def skip_csrf_meta_tags?
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ module ContextHelper
|
|||||||
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
voters_count: { 'toot' => 'http://joinmastodon.org/ns#', 'votersCount' => 'toot:votersCount' },
|
||||||
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
suspended: { 'toot' => 'http://joinmastodon.org/ns#', 'suspended' => 'toot:suspended' },
|
||||||
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
attribution_domains: { 'toot' => 'http://joinmastodon.org/ns#', 'attributionDomains' => { '@id' => 'toot:attributionDomains', '@type' => '@id' } },
|
||||||
|
interaction_policies: {
|
||||||
|
'gts' => 'https://gotosocial.org/ns#',
|
||||||
|
'interactionPolicy' => { '@id' => 'gts:interactionPolicy', '@type' => '@id' },
|
||||||
|
'canQuote' => { '@id' => 'gts:canQuote', '@type' => '@id' },
|
||||||
|
'automaticApproval' => { '@id' => 'gts:automaticApproval', '@type' => '@id' },
|
||||||
|
'manualApproval' => { '@id' => 'gts:manualApproval', '@type' => '@id' },
|
||||||
|
},
|
||||||
}.freeze
|
}.freeze
|
||||||
|
|
||||||
def full_context
|
def full_context
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import axios from 'axios';
|
|||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
async function checkConfirmation() {
|
async function checkConfirmation() {
|
||||||
const response = await axios.get('/api/v1/emails/check_confirmation');
|
const response = await axios.get('/api/v1/emails/check_confirmation', {
|
||||||
|
headers: { Accept: 'application/json' },
|
||||||
|
withCredentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (response.data) {
|
if (response.status === 200 && response.data === true) {
|
||||||
window.location.href = '/start';
|
window.location.href = '/start';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,6 +72,17 @@ export function normalizeStatus(status, normalOldStatus, settings) {
|
|||||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||||
normalStatus.hidden = (spoilerText.length > 0 || normalStatus.sensitive) && autoHideCW(settings, spoilerText);
|
normalStatus.hidden = (spoilerText.length > 0 || normalStatus.sensitive) && autoHideCW(settings, spoilerText);
|
||||||
|
|
||||||
|
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
|
||||||
|
normalStatus.url = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalStatus.url ||= normalStatus.uri;
|
||||||
|
|
||||||
|
normalStatus.media_attachments.forEach(item => {
|
||||||
|
if (item.remote_url && !(item.remote_url.startsWith('http://') || item.remote_url.startsWith('https://')))
|
||||||
|
item.remote_url = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalOldStatus) {
|
if (normalOldStatus) {
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import axios from 'axios';
|
|||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
|
|
||||||
async function checkConfirmation() {
|
async function checkConfirmation() {
|
||||||
const response = await axios.get('/api/v1/emails/check_confirmation');
|
const response = await axios.get('/api/v1/emails/check_confirmation', {
|
||||||
|
headers: { Accept: 'application/json' },
|
||||||
|
withCredentials: true,
|
||||||
|
});
|
||||||
|
|
||||||
if (response.data) {
|
if (response.status === 200 && response.data === true) {
|
||||||
window.location.href = '/start';
|
window.location.href = '/start';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,6 +169,15 @@ class LocalSettingsPage extends PureComponent {
|
|||||||
<FormattedMessage id='settings.wide_view' defaultMessage='Wide view (Desktop mode only)' />
|
<FormattedMessage id='settings.wide_view' defaultMessage='Wide view (Desktop mode only)' />
|
||||||
<span className='hint'><FormattedMessage id='settings.wide_view_hint' defaultMessage='Stretches columns to better fill the available space.' /></span>
|
<span className='hint'><FormattedMessage id='settings.wide_view_hint' defaultMessage='Stretches columns to better fill the available space.' /></span>
|
||||||
</LocalSettingsPageItem>
|
</LocalSettingsPageItem>
|
||||||
|
<LocalSettingsPageItem
|
||||||
|
settings={settings}
|
||||||
|
item={['fullwidth_columns']}
|
||||||
|
id='mastodon-settings--fullwidth_columns'
|
||||||
|
onChange={onChange}
|
||||||
|
>
|
||||||
|
<FormattedMessage id='settings.fullwidth_view' defaultMessage='Stretch columns to full width (Desktop mode only)' />
|
||||||
|
<span className='hint'><FormattedMessage id='settings.fullwidth_view_hint' defaultMessage='Stretches columns to fill all the available space.' /></span>
|
||||||
|
</LocalSettingsPageItem>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ const mapStateToProps = state => ({
|
|||||||
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
|
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||||
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
|
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
|
||||||
isWide: state.getIn(['local_settings', 'stretch']),
|
isWide: state.getIn(['local_settings', 'stretch']),
|
||||||
|
fullWidthColumns: state.getIn(['local_settings', 'fullwidth_columns']),
|
||||||
unreadNotifications: selectUnreadNotificationGroupsCount(state),
|
unreadNotifications: selectUnreadNotificationGroupsCount(state),
|
||||||
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
|
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
|
||||||
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
|
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
|
||||||
@@ -270,6 +271,7 @@ class UI extends PureComponent {
|
|||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
isWide: PropTypes.bool,
|
isWide: PropTypes.bool,
|
||||||
|
fullWidthColumns: PropTypes.bool,
|
||||||
systemFontUi: PropTypes.bool,
|
systemFontUi: PropTypes.bool,
|
||||||
isComposing: PropTypes.bool,
|
isComposing: PropTypes.bool,
|
||||||
hasComposingText: PropTypes.bool,
|
hasComposingText: PropTypes.bool,
|
||||||
@@ -608,6 +610,7 @@ class UI extends PureComponent {
|
|||||||
|
|
||||||
const className = classNames('ui', {
|
const className = classNames('ui', {
|
||||||
'wide': isWide,
|
'wide': isWide,
|
||||||
|
'fullwidth-columns': this.props.fullWidthColumns,
|
||||||
'system-font': this.props.systemFontUi,
|
'system-font': this.props.systemFontUi,
|
||||||
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,
|
'hicolor-privacy-icons': this.props.hicolorPrivacyIcons,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -90,6 +90,8 @@
|
|||||||
"settings.enable_collapsed": "Enable collapsed toots",
|
"settings.enable_collapsed": "Enable collapsed toots",
|
||||||
"settings.enable_collapsed_hint": "Collapsed posts have parts of their contents hidden to take up less screen space. This is distinct from the Content Warning feature",
|
"settings.enable_collapsed_hint": "Collapsed posts have parts of their contents hidden to take up less screen space. This is distinct from the Content Warning feature",
|
||||||
"settings.enable_content_warnings_auto_unfold": "Automatically unfold content-warnings",
|
"settings.enable_content_warnings_auto_unfold": "Automatically unfold content-warnings",
|
||||||
|
"settings.fullwidth_view": "Stretch columns to full width (Desktop mode only)",
|
||||||
|
"settings.fullwidth_view_hint": "Stretches columns to fill all the available space.",
|
||||||
"settings.general": "General",
|
"settings.general": "General",
|
||||||
"settings.hicolor_privacy_icons": "High color privacy icons",
|
"settings.hicolor_privacy_icons": "High color privacy icons",
|
||||||
"settings.hicolor_privacy_icons.hint": "Display privacy icons in bright and easily distinguishable colors",
|
"settings.hicolor_privacy_icons.hint": "Display privacy icons in bright and easily distinguishable colors",
|
||||||
|
|||||||
@@ -150,5 +150,10 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
|||||||
),
|
),
|
||||||
note_emojified: emojify(accountJSON.note, emojiMap),
|
note_emojified: emojify(accountJSON.note, emojiMap),
|
||||||
note_plain: unescapeHTML(accountJSON.note),
|
note_plain: unescapeHTML(accountJSON.note),
|
||||||
|
url:
|
||||||
|
accountJSON.url.startsWith('http://') ||
|
||||||
|
accountJSON.url.startsWith('https://')
|
||||||
|
? accountJSON.url
|
||||||
|
: accountJSON.uri,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import { ACCOUNT_LOOKUP_FAIL } from '../actions/accounts';
|
|||||||
import { importAccounts } from '../actions/accounts_typed';
|
import { importAccounts } from '../actions/accounts_typed';
|
||||||
import { domain } from '../initial_state';
|
import { domain } from '../initial_state';
|
||||||
|
|
||||||
export const normalizeForLookup = str => {
|
const pattern = new RegExp(`@${domain}$`, 'gi');
|
||||||
str = str.toLowerCase();
|
|
||||||
const trailingIndex = str.indexOf(`@${domain.toLowerCase()}`);
|
export const normalizeForLookup = str =>
|
||||||
return (trailingIndex > 0) ? str.slice(0, trailingIndex) : str;
|
str.toLowerCase().replace(pattern, '');
|
||||||
};
|
|
||||||
|
|
||||||
const initialState = ImmutableMap();
|
const initialState = ImmutableMap();
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { LOCAL_SETTING_CHANGE, LOCAL_SETTING_DELETE } from 'flavours/glitch/acti
|
|||||||
import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
|
import { STORE_HYDRATE } from 'flavours/glitch/actions/store';
|
||||||
|
|
||||||
const initialState = ImmutableMap({
|
const initialState = ImmutableMap({
|
||||||
|
fullwidth_columns: false,
|
||||||
stretch : true,
|
stretch : true,
|
||||||
side_arm : 'none',
|
side_arm : 'none',
|
||||||
side_arm_reply_mode : 'keep',
|
side_arm_reply_mode : 'keep',
|
||||||
|
|||||||
@@ -7477,6 +7477,13 @@ img.modal-warning {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fullwidth-columns .columns-area:not(.columns-area--mobile) {
|
||||||
|
.column {
|
||||||
|
flex: auto;
|
||||||
|
max-width: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.media-gallery__actions {
|
.media-gallery__actions {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 6px;
|
top: 6px;
|
||||||
|
|||||||
@@ -80,6 +80,17 @@ export function normalizeStatus(status, normalOldStatus) {
|
|||||||
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
normalStatus.contentHtml = emojify(normalStatus.content, emojiMap);
|
||||||
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
normalStatus.spoilerHtml = emojify(escapeTextContentForBrowser(spoilerText), emojiMap);
|
||||||
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
normalStatus.hidden = expandSpoilers ? false : spoilerText.length > 0 || normalStatus.sensitive;
|
||||||
|
|
||||||
|
if (normalStatus.url && !(normalStatus.url.startsWith('http://') || normalStatus.url.startsWith('https://'))) {
|
||||||
|
normalStatus.url = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
normalStatus.url ||= normalStatus.uri;
|
||||||
|
|
||||||
|
normalStatus.media_attachments.forEach(item => {
|
||||||
|
if (item.remote_url && !(item.remote_url.startsWith('http://') || item.remote_url.startsWith('https://')))
|
||||||
|
item.remote_url = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normalOldStatus) {
|
if (normalOldStatus) {
|
||||||
|
|||||||
@@ -150,5 +150,10 @@ export function createAccountFromServerJSON(serverJSON: ApiAccountJSON) {
|
|||||||
),
|
),
|
||||||
note_emojified: emojify(accountJSON.note, emojiMap),
|
note_emojified: emojify(accountJSON.note, emojiMap),
|
||||||
note_plain: unescapeHTML(accountJSON.note),
|
note_plain: unescapeHTML(accountJSON.note),
|
||||||
|
url:
|
||||||
|
accountJSON.url.startsWith('http://') ||
|
||||||
|
accountJSON.url.startsWith('https://')
|
||||||
|
? accountJSON.url
|
||||||
|
: accountJSON.uri,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,13 +15,15 @@ class ActivityPub::Parser::MediaAttachmentParser
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remote_url
|
def remote_url
|
||||||
Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
url = Addressable::URI.parse(@json['url'])&.normalize&.to_s
|
||||||
|
url unless unsupported_uri_scheme?(url)
|
||||||
rescue Addressable::URI::InvalidURIError
|
rescue Addressable::URI::InvalidURIError
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def thumbnail_remote_url
|
def thumbnail_remote_url
|
||||||
Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
url = Addressable::URI.parse(@json['icon'].is_a?(Hash) ? @json['icon']['url'] : @json['icon'])&.normalize&.to_s
|
||||||
|
url unless unsupported_uri_scheme?(url)
|
||||||
rescue Addressable::URI::InvalidURIError
|
rescue Addressable::URI::InvalidURIError
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,7 +28,10 @@ class ActivityPub::Parser::StatusParser
|
|||||||
end
|
end
|
||||||
|
|
||||||
def url
|
def url
|
||||||
url_to_href(@object['url'], 'text/html') if @object['url'].present?
|
return if @object['url'].blank?
|
||||||
|
|
||||||
|
url = url_to_href(@object['url'], 'text/html')
|
||||||
|
url unless unsupported_uri_scheme?(url)
|
||||||
end
|
end
|
||||||
|
|
||||||
def text
|
def text
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ require 'singleton'
|
|||||||
|
|
||||||
class ActivityPub::TagManager
|
class ActivityPub::TagManager
|
||||||
include Singleton
|
include Singleton
|
||||||
|
include JsonLdHelper
|
||||||
include RoutingHelper
|
include RoutingHelper
|
||||||
|
|
||||||
CONTEXT = 'https://www.w3.org/ns/activitystreams'
|
CONTEXT = 'https://www.w3.org/ns/activitystreams'
|
||||||
@@ -17,7 +18,7 @@ class ActivityPub::TagManager
|
|||||||
end
|
end
|
||||||
|
|
||||||
def url_for(target)
|
def url_for(target)
|
||||||
return target.url if target.respond_to?(:local?) && !target.local?
|
return unsupported_uri_scheme?(target.url) ? nil : target.url if target.respond_to?(:local?) && !target.local?
|
||||||
|
|
||||||
return unless target.respond_to?(:object_type)
|
return unless target.respond_to?(:object_type)
|
||||||
|
|
||||||
|
|||||||
@@ -6,14 +6,13 @@
|
|||||||
class HttpSignatureDraft
|
class HttpSignatureDraft
|
||||||
REQUEST_TARGET = '(request-target)'
|
REQUEST_TARGET = '(request-target)'
|
||||||
|
|
||||||
def initialize(keypair, key_id, full_path: true)
|
def initialize(keypair, key_id)
|
||||||
@keypair = keypair
|
@keypair = keypair
|
||||||
@key_id = key_id
|
@key_id = key_id
|
||||||
@full_path = full_path
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def request_target(verb, url)
|
def request_target(verb, url)
|
||||||
if url.query.nil? || !@full_path
|
if url.query.nil?
|
||||||
"#{verb} #{url.path}"
|
"#{verb} #{url.path}"
|
||||||
else
|
else
|
||||||
"#{verb} #{url.path}?#{url.query}"
|
"#{verb} #{url.path}?#{url.query}"
|
||||||
|
|||||||
@@ -75,7 +75,6 @@ class Request
|
|||||||
@url = Addressable::URI.parse(url).normalize
|
@url = Addressable::URI.parse(url).normalize
|
||||||
@http_client = options.delete(:http_client)
|
@http_client = options.delete(:http_client)
|
||||||
@allow_local = options.delete(:allow_local)
|
@allow_local = options.delete(:allow_local)
|
||||||
@full_path = !options.delete(:omit_query_string)
|
|
||||||
@options = {
|
@options = {
|
||||||
follow: {
|
follow: {
|
||||||
max_hops: 3,
|
max_hops: 3,
|
||||||
@@ -102,7 +101,7 @@ class Request
|
|||||||
|
|
||||||
key_id = ActivityPub::TagManager.instance.key_uri_for(actor)
|
key_id = ActivityPub::TagManager.instance.key_uri_for(actor)
|
||||||
keypair = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : actor.keypair
|
keypair = sign_with.present? ? OpenSSL::PKey::RSA.new(sign_with) : actor.keypair
|
||||||
@signing = HttpSignatureDraft.new(keypair, key_id, full_path: @full_path)
|
@signing = HttpSignatureDraft.new(keypair, key_id)
|
||||||
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,20 +37,7 @@ class ActivityPub::FetchRepliesService < BaseService
|
|||||||
return unless @allow_synchronous_requests
|
return unless @allow_synchronous_requests
|
||||||
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
|
return if non_matching_uri_hosts?(@account.uri, collection_or_uri)
|
||||||
|
|
||||||
# NOTE: For backward compatibility reasons, Mastodon signs outgoing
|
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
||||||
# queries incorrectly by default.
|
|
||||||
#
|
|
||||||
# While this is relevant for all URLs with query strings, this is
|
|
||||||
# the only code path where this happens in practice.
|
|
||||||
#
|
|
||||||
# Therefore, retry with correct signatures if this fails.
|
|
||||||
begin
|
|
||||||
fetch_resource_without_id_validation(collection_or_uri, nil, true)
|
|
||||||
rescue Mastodon::UnexpectedResponseError => e
|
|
||||||
raise unless e.response && e.response.code == 401 && Addressable::URI.parse(collection_or_uri).query.present?
|
|
||||||
|
|
||||||
fetch_resource_without_id_validation(collection_or_uri, nil, true, request_options: { omit_query_string: false })
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def filtered_replies
|
def filtered_replies
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ class ActivityPub::DeliveryWorker
|
|||||||
stoplight_wrapper.run do
|
stoplight_wrapper.run do
|
||||||
request_pool.with(@host) do |http_client|
|
request_pool.with(@host) do |http_client|
|
||||||
build_request(http_client).perform do |response|
|
build_request(http_client).perform do |response|
|
||||||
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response)
|
raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) || unsalvageable_authorization_failure?(response)
|
||||||
|
|
||||||
@performed = true
|
@performed = true
|
||||||
end
|
end
|
||||||
@@ -70,6 +70,10 @@ class ActivityPub::DeliveryWorker
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unsalvageable_authorization_failure?(response)
|
||||||
|
@source_account.permanently_unavailable? && response.code == 401
|
||||||
|
end
|
||||||
|
|
||||||
def stoplight_wrapper
|
def stoplight_wrapper
|
||||||
Stoplight(@inbox_url)
|
Stoplight(@inbox_url)
|
||||||
.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
|
.with_threshold(STOPLIGHT_FAILURE_THRESHOLD)
|
||||||
|
|||||||
16
config/initializers/deprecations.rb
Normal file
16
config/initializers/deprecations.rb
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
if ENV['REDIS_NAMESPACE']
|
||||||
|
es_configured = ENV['ES_ENABLED'] == 'true' || ENV.fetch('ES_HOST', 'localhost') != 'localhost' || ENV.fetch('ES_PORT', '9200') != '9200' || ENV.fetch('ES_PASS', 'password') != 'password'
|
||||||
|
|
||||||
|
warn <<~MESSAGE
|
||||||
|
WARNING: the REDIS_NAMESPACE environment variable is deprecated and will be removed in Mastodon 4.4.0.
|
||||||
|
|
||||||
|
Please see documentation at https://github.com/mastodon/redis_namespace_migration
|
||||||
|
MESSAGE
|
||||||
|
|
||||||
|
warn <<~MESSAGE if es_configured && !ENV['ES_PREFIX']
|
||||||
|
|
||||||
|
In addition, as REDIS_NAMESPACE is being used as a prefix for Elasticsearch, please do not forget to set ES_PREFIX to "#{ENV.fetch('REDIS_NAMESPACE')}".
|
||||||
|
MESSAGE
|
||||||
|
end
|
||||||
@@ -59,7 +59,7 @@ services:
|
|||||||
web:
|
web:
|
||||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||||
# build: .
|
# build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.3.7
|
image: ghcr.io/glitch-soc/mastodon:v4.3.8
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec puma -C config/puma.rb
|
command: bundle exec puma -C config/puma.rb
|
||||||
@@ -83,7 +83,7 @@ services:
|
|||||||
# build:
|
# build:
|
||||||
# dockerfile: ./streaming/Dockerfile
|
# dockerfile: ./streaming/Dockerfile
|
||||||
# context: .
|
# context: .
|
||||||
image: ghcr.io/mastodon/mastodon-streaming:v4.3.7
|
image: ghcr.io/glitch-soc/mastodon-streaming:v4.3.8
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: node ./streaming/index.js
|
command: node ./streaming/index.js
|
||||||
@@ -102,7 +102,7 @@ services:
|
|||||||
sidekiq:
|
sidekiq:
|
||||||
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
# You can uncomment the following line if you want to not use the prebuilt image, for example if you have local code changes
|
||||||
# build: .
|
# build: .
|
||||||
image: ghcr.io/mastodon/mastodon:v4.3.7
|
image: ghcr.io/glitch-soc/mastodon:v4.3.8
|
||||||
restart: always
|
restart: always
|
||||||
env_file: .env.production
|
env_file: .env.production
|
||||||
command: bundle exec sidekiq
|
command: bundle exec sidekiq
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module Mastodon
|
|||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
7
|
8
|
||||||
end
|
end
|
||||||
|
|
||||||
def default_prerelease
|
def default_prerelease
|
||||||
|
|||||||
Reference in New Issue
Block a user