Merge pull request #3647 from glitch-soc/glitch-soc/merge-4.6
Merge upstream changes up to 70ca3d5ee7 into stable-4.6
This commit is contained in:
@@ -13,6 +13,7 @@ runs:
|
||||
- name: Install system dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
sudo sed -i s:azure\.archive\.ubuntu\.com:archive.ubuntu.com:g /etc/apt/apt-mirrors.txt
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
libicu-dev \
|
||||
|
||||
+1
-1
@@ -399,7 +399,7 @@ RUN \
|
||||
|
||||
RUN \
|
||||
# Precompile bootsnap code for faster Rails startup
|
||||
bundle exec bootsnap precompile --gemfile app/ lib/;
|
||||
bundle exec bootsnap precompile --gemfile app/ lib/ config/;
|
||||
|
||||
RUN \
|
||||
# Pre-create and chown system volume to Mastodon user
|
||||
|
||||
+1
-1
@@ -16,6 +16,6 @@ A "vulnerability in Mastodon" is a vulnerability in the code distributed through
|
||||
| Version | Supported |
|
||||
| ------- | ---------------- |
|
||||
| 4.6.0 | Yes |
|
||||
| 4.5.x | Yes |
|
||||
| 4.5.x | Until 2027-02-20 |
|
||||
| 4.4.x | Until 2026-12-17 |
|
||||
| < 4.4 | No |
|
||||
|
||||
@@ -12,7 +12,7 @@ module Admin
|
||||
@pending_tags_count = pending_tags.async_count
|
||||
@pending_users_count = User.pending.async_count
|
||||
@system_checks = Admin::SystemCheck.perform(current_user)
|
||||
@time_period = (29.days.ago.to_date...Time.now.utc.to_date)
|
||||
@time_period = (29.days.ago.to_date..Time.now.utc.to_date)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -13,7 +13,7 @@ class Admin::Instances::ModerationNotesController < Admin::BaseController
|
||||
redirect_to admin_instance_path(@instance.domain, anchor: helpers.dom_id(@instance_moderation_note)), notice: I18n.t('admin.instances.moderation_notes.created_msg')
|
||||
else
|
||||
@instance_moderation_notes = @instance.moderation_notes.includes(:account).chronological
|
||||
@time_period = (6.days.ago.to_date...Time.now.utc.to_date)
|
||||
@time_period = (6.days.ago.to_date..Time.now.utc.to_date)
|
||||
@action_logs = Admin::ActionLogFilter.new(target_domain: @instance.domain).results.limit(5)
|
||||
|
||||
render 'admin/instances/show'
|
||||
|
||||
@@ -17,7 +17,7 @@ module Admin
|
||||
|
||||
@instance_moderation_note = @instance.moderation_notes.new
|
||||
@instance_moderation_notes = @instance.moderation_notes.includes(:account).chronological
|
||||
@time_period = (6.days.ago.to_date...Time.now.utc.to_date)
|
||||
@time_period = (6.days.ago.to_date..Time.now.utc.to_date)
|
||||
@action_logs = Admin::ActionLogFilter.new(target_domain: @instance.domain).results.limit(LOGS_LIMIT)
|
||||
end
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ module Admin
|
||||
end
|
||||
|
||||
def report_range
|
||||
(PERIOD_DAYS.ago.to_date...Time.now.utc.to_date)
|
||||
(PERIOD_DAYS.ago.to_date..Time.now.utc.to_date)
|
||||
end
|
||||
|
||||
def tag_params
|
||||
|
||||
@@ -6,6 +6,14 @@ describe('textAtCursorMatchesToken', () => {
|
||||
['#hashtag', 7, ['#']],
|
||||
[1, '#hashtag'],
|
||||
],
|
||||
[
|
||||
['@alice', 6, ['@']],
|
||||
[1, '@alice'],
|
||||
],
|
||||
[
|
||||
['@alice', 6, ['@']],
|
||||
[1, '@alice'],
|
||||
],
|
||||
[
|
||||
['#hash tag', 8, ['#']],
|
||||
[1, '#hash tag'],
|
||||
@@ -24,7 +32,35 @@ describe('textAtCursorMatchesToken', () => {
|
||||
],
|
||||
[
|
||||
['#ハッシュ タグ', 7, ['#']],
|
||||
[1, '#ハッシュ タグ'],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice reply', 12, ['@']],
|
||||
[1, '@alice reply'],
|
||||
],
|
||||
[
|
||||
['@alice 这是我输入的回复内容', 17, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice これは本文', 12, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice 이것은답변입니다', 15, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice これは本文', 12, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@алиса', 6, ['@']],
|
||||
[1, '@алиса'],
|
||||
],
|
||||
[
|
||||
['@алиса пример', 13, ['@']],
|
||||
[1, '@алиса пример'],
|
||||
],
|
||||
] as const)(
|
||||
'textAtCursorMatchesToken(%s) is %o',
|
||||
|
||||
@@ -8,7 +8,7 @@ export const textAtCursorMatchesToken = (
|
||||
let word: string;
|
||||
|
||||
const regex = new RegExp(
|
||||
`[${searchTokens.join('')}${WORD}+-]+(\\s[${WORD}]+)?$`,
|
||||
`[${searchTokens.join('')}${WORD}+-]+(\\s[\\p{Script=Latin}\\p{Script=Cyrillic}\\p{M}]+)?$`,
|
||||
'iu',
|
||||
);
|
||||
const left = str.slice(0, caretPosition).search(regex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const HASHTAG_SEPARATORS = '_\\u00b7\\u200c';
|
||||
const ALPHA = '\\p{L}\\p{M}';
|
||||
export const ALPHA = '\\p{L}\\p{M}';
|
||||
export const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}';
|
||||
|
||||
const buildHashtagPatternRegex = () => {
|
||||
|
||||
@@ -6,6 +6,14 @@ describe('textAtCursorMatchesToken', () => {
|
||||
['#hashtag', 7, ['#']],
|
||||
[1, '#hashtag'],
|
||||
],
|
||||
[
|
||||
['@alice', 6, ['@']],
|
||||
[1, '@alice'],
|
||||
],
|
||||
[
|
||||
['@alice', 6, ['@']],
|
||||
[1, '@alice'],
|
||||
],
|
||||
[
|
||||
['#hash tag', 8, ['#']],
|
||||
[1, '#hash tag'],
|
||||
@@ -24,7 +32,35 @@ describe('textAtCursorMatchesToken', () => {
|
||||
],
|
||||
[
|
||||
['#ハッシュ タグ', 7, ['#']],
|
||||
[1, '#ハッシュ タグ'],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice reply', 12, ['@']],
|
||||
[1, '@alice reply'],
|
||||
],
|
||||
[
|
||||
['@alice 这是我输入的回复内容', 17, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice これは本文', 12, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice 이것은답변입니다', 15, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@alice これは本文', 12, ['@']],
|
||||
[null, null],
|
||||
],
|
||||
[
|
||||
['@алиса', 6, ['@']],
|
||||
[1, '@алиса'],
|
||||
],
|
||||
[
|
||||
['@алиса пример', 13, ['@']],
|
||||
[1, '@алиса пример'],
|
||||
],
|
||||
] as const)(
|
||||
'textAtCursorMatchesToken(%s) is %o',
|
||||
|
||||
@@ -8,7 +8,7 @@ export const textAtCursorMatchesToken = (
|
||||
let word: string;
|
||||
|
||||
const regex = new RegExp(
|
||||
`[${searchTokens.join('')}${WORD}+-]+(\\s[${WORD}]+)?$`,
|
||||
`[${searchTokens.join('')}${WORD}+-]+(\\s[\\p{Script=Latin}\\p{Script=Cyrillic}\\p{M}]+)?$`,
|
||||
'iu',
|
||||
);
|
||||
const left = str.slice(0, caretPosition).search(regex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
const HASHTAG_SEPARATORS = '_\\u00b7\\u200c';
|
||||
const ALPHA = '\\p{L}\\p{M}';
|
||||
export const ALPHA = '\\p{L}\\p{M}';
|
||||
export const WORD = '\\p{L}\\p{M}\\p{N}\\p{Pc}';
|
||||
|
||||
const buildHashtagPatternRegex = () => {
|
||||
|
||||
@@ -39,7 +39,7 @@ class ActivityTracker
|
||||
end
|
||||
|
||||
def sum(start_at, end_at = Time.now.utc)
|
||||
keys = (start_at.to_date...end_at.to_date).flat_map { |date| [key_at(date.to_time(:utc)), legacy_key_at(date)] }.uniq
|
||||
keys = (start_at.to_date..end_at.to_date).flat_map { |date| [key_at(date.to_time(:utc)), legacy_key_at(date)] }.uniq
|
||||
|
||||
case @type
|
||||
when :basic
|
||||
|
||||
@@ -97,7 +97,7 @@ class Admin::Metrics::Measure::BaseMeasure
|
||||
end
|
||||
|
||||
def previous_time_period
|
||||
((@start_at.to_date - length_of_period)..(@end_at.to_date - length_of_period))
|
||||
((@start_at.to_date - (length_of_period + 1))..(@end_at.to_date - (length_of_period + 1)))
|
||||
end
|
||||
|
||||
def length_of_period
|
||||
|
||||
@@ -298,6 +298,8 @@ class ActivityPub::ProcessAccountService < BaseService
|
||||
next unless value['owner'] == @account.uri
|
||||
|
||||
key = value['publicKeyPem']
|
||||
next if key.nil?
|
||||
|
||||
{ type: :rsa, public_key: key, uri: key_id }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,6 +17,10 @@ RSpec.describe Admin::Metrics::Measure::TagUsesMeasure do
|
||||
let(:bob) { Fabricate(:account, domain: 'bob.example') }
|
||||
|
||||
before do
|
||||
2.times do
|
||||
travel_to(3.days.ago) { add_tag_history(alice) }
|
||||
end
|
||||
|
||||
3.times do
|
||||
travel_to(2.days.ago) { add_tag_history(alice) }
|
||||
end
|
||||
@@ -40,6 +44,8 @@ RSpec.describe Admin::Metrics::Measure::TagUsesMeasure do
|
||||
include(date: 1.day.ago.midnight.to_time, value: '4'),
|
||||
include(date: 0.days.ago.midnight.to_time, value: '1')
|
||||
)
|
||||
expect(subject.previous_total)
|
||||
.to eq 2
|
||||
end
|
||||
|
||||
def add_tag_history(account)
|
||||
|
||||
@@ -4,7 +4,7 @@ require 'rails_helper'
|
||||
|
||||
RSpec.describe PrivateAddressCheck do
|
||||
describe 'private_address?' do
|
||||
let(:private_ips) { %w(192.168.1.7 0.0.0.0 127.0.0.1 ::ffff:0.0.0.1) }
|
||||
let(:private_ips) { %w(192.168.1.7 0.0.0.0 127.0.0.1 ::ffff:0.0.0.1 ::127.0.0.1 ::ffff:127.0.0.1 ::ffff:10.0.0.1 ::ffff:169.254.169.254 ::) }
|
||||
|
||||
it 'returns true for private addresses' do
|
||||
expect(private_ips)
|
||||
|
||||
@@ -109,6 +109,46 @@ RSpec.describe ActivityPub::ProcessCollectionService do
|
||||
expect(ActivityPub::Activity).to_not have_received(:factory)
|
||||
end
|
||||
|
||||
context 'when receiving a status with an unsupported JSON-LD keyword' do
|
||||
let(:payload) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
id: 'foo',
|
||||
type: 'Announce',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(actor),
|
||||
'@reverse': {
|
||||
object: {
|
||||
type: 'Undo',
|
||||
id: 'bar',
|
||||
actor: ActivityPub::TagManager.instance.uri_for(actor),
|
||||
},
|
||||
},
|
||||
object: {
|
||||
id: 'bar',
|
||||
type: 'Note',
|
||||
content: 'Lorem ipsum',
|
||||
},
|
||||
signature: {
|
||||
type: 'RsaSignature2017',
|
||||
creator: "#{ActivityPub::TagManager.instance.uri_for(actor)}#foo",
|
||||
created: '2022-03-09T21:57:25Z',
|
||||
signatureValue: 'foo',
|
||||
},
|
||||
}
|
||||
end
|
||||
|
||||
it 'does not process payload' do
|
||||
signature_double = instance_double(ActivityPub::LinkedDataSignature, verify_actor!: nil)
|
||||
allow(ActivityPub::LinkedDataSignature).to receive(:new).and_return(signature_double)
|
||||
allow(ActivityPub::Activity).to receive(:factory)
|
||||
|
||||
subject.call(json, forwarder)
|
||||
|
||||
expect(signature_double).to_not have_received(:verify_actor!)
|
||||
expect(ActivityPub::Activity).to_not have_received(:factory)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when receiving a fabricated status' do
|
||||
let!(:actor) do
|
||||
Fabricate(:account,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe EmailAddressValidator do
|
||||
subject { record_class.new }
|
||||
|
||||
context 'with no options' do
|
||||
let(:record_class) do
|
||||
Class.new do
|
||||
include ActiveModel::Validations
|
||||
|
||||
def self.name = 'Record'
|
||||
|
||||
attr_accessor :email
|
||||
|
||||
validates :email, email_address: true
|
||||
end
|
||||
end
|
||||
|
||||
it { is_expected.to allow_value('foo@example.com').for(:email) }
|
||||
it { is_expected.to_not allow_value('foo @ example.com').for(:email) }
|
||||
it { is_expected.to_not allow_value('foo@example.com%foo.example.com').for(:email) }
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user