mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-15 16:59:41 +00:00
Merge commit 'a13756148d353c7479f68e65a210f6d88d26c785' into glitch-soc/merge-upstream
Conflicts: - `app/views/layouts/embedded.html.haml`: Upstream made a change to javascript tags next to lines changed in glitch-soc because of the theming system. Added the javascript entrypoint upstream added. - `app/views/layouts/error.html.haml`: Upstream made a change to javascript tags next to lines changed in glitch-soc because of the theming system. Added the javascript entrypoint upstream added.
This commit is contained in:
@@ -36,4 +36,15 @@ RSpec.describe Rule do
|
||||
.to change { described_class.ordered.pluck(:text) }.from(%w(foo baz bar)).to(%w(foo bar baz))
|
||||
end
|
||||
end
|
||||
|
||||
describe '#translation_for' do
|
||||
let!(:rule) { Fabricate(:rule, text: 'This is a rule', hint: 'This is an explanation of the rule') }
|
||||
let!(:translation) { Fabricate(:rule_translation, rule: rule, text: 'Ceci est une règle', hint: 'Ceci est une explication de la règle', language: 'fr') }
|
||||
|
||||
it 'returns the expected translation, including fallbacks' do
|
||||
expect(rule.translation_for(:en)).to have_attributes(text: rule.text, hint: rule.hint)
|
||||
expect(rule.translation_for(:fr)).to have_attributes(text: translation.text, hint: translation.hint)
|
||||
expect(rule.translation_for(:'fr-CA')).to have_attributes(text: translation.text, hint: translation.hint)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -67,31 +67,59 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService do
|
||||
type: 'Collection',
|
||||
id: actor.featured_collection_url,
|
||||
items: items,
|
||||
}.with_indifferent_access
|
||||
end
|
||||
|
||||
shared_examples 'sets pinned posts' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null), headers: { 'Content-Type': 'application/activity+json' })
|
||||
|
||||
subject.call(actor, note: true, hashtag: false)
|
||||
end
|
||||
|
||||
it 'sets expected posts as pinned posts' do
|
||||
expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly(
|
||||
'https://example.com/account/pinned/known',
|
||||
'https://example.com/account/pinned/unknown-inlined',
|
||||
'https://example.com/account/pinned/unknown-reachable'
|
||||
)
|
||||
expect(actor.pinned_statuses).to_not include(known_status)
|
||||
end
|
||||
}.deep_stringify_keys
|
||||
end
|
||||
|
||||
describe '#call' do
|
||||
subject { described_class.new.call(actor, note: true, hashtag: false) }
|
||||
|
||||
shared_examples 'sets pinned posts' do
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/account/pinned/known').to_return(status: 200, body: Oj.dump(status_json_pinned_known), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-inlined').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_inlined), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-unreachable').to_return(status: 404)
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
|
||||
stub_request(:get, 'https://example.com/account/collections/featured').to_return(status: 200, body: Oj.dump(featured_with_null), headers: { 'Content-Type': 'application/activity+json' })
|
||||
|
||||
subject
|
||||
end
|
||||
|
||||
it 'sets expected posts as pinned posts' do
|
||||
expect(actor.pinned_statuses.pluck(:uri)).to contain_exactly(
|
||||
'https://example.com/account/pinned/known',
|
||||
'https://example.com/account/pinned/unknown-inlined',
|
||||
'https://example.com/account/pinned/unknown-reachable'
|
||||
)
|
||||
expect(actor.pinned_statuses).to_not include(known_status)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when passing the collection via an argument' do
|
||||
subject { described_class.new.call(actor, note: true, hashtag: false, collection: collection_or_uri) }
|
||||
|
||||
context 'when the collection is an URL' do
|
||||
let(:collection_or_uri) { actor.featured_collection_url }
|
||||
|
||||
before do
|
||||
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||
end
|
||||
|
||||
it_behaves_like 'sets pinned posts'
|
||||
end
|
||||
|
||||
context 'when the collection is inlined' do
|
||||
let(:collection_or_uri) do
|
||||
{
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
type: 'Collection',
|
||||
items: items,
|
||||
}.deep_stringify_keys
|
||||
end
|
||||
|
||||
it_behaves_like 'sets pinned posts'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the endpoint is a Collection' do
|
||||
before do
|
||||
stub_request(:get, actor.featured_collection_url).to_return(status: 200, body: Oj.dump(payload), headers: { 'Content-Type': 'application/activity+json' })
|
||||
@@ -121,7 +149,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService do
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
|
||||
subject.call(actor, note: true, hashtag: false)
|
||||
subject
|
||||
end
|
||||
|
||||
it 'sets expected posts as pinned posts' do
|
||||
@@ -157,7 +185,7 @@ RSpec.describe ActivityPub::FetchFeaturedCollectionService do
|
||||
|
||||
before do
|
||||
stub_request(:get, 'https://example.com/account/pinned/unknown-reachable').to_return(status: 200, body: Oj.dump(status_json_pinned_unknown_reachable), headers: { 'Content-Type': 'application/activity+json' })
|
||||
subject.call(actor, note: true, hashtag: false)
|
||||
subject
|
||||
end
|
||||
|
||||
it 'sets expected posts as pinned posts' do
|
||||
|
||||
@@ -83,6 +83,27 @@ RSpec.describe ActivityPub::ProcessAccountService do
|
||||
end
|
||||
end
|
||||
|
||||
context 'with inlined feature collection' do
|
||||
let(:payload) do
|
||||
{
|
||||
id: 'https://foo.test',
|
||||
type: 'Actor',
|
||||
inbox: 'https://foo.test/inbox',
|
||||
featured: {
|
||||
type: 'OrderedCollection',
|
||||
orderedItems: ['https://example.com/statuses/1'],
|
||||
},
|
||||
}.deep_stringify_keys
|
||||
end
|
||||
|
||||
it 'queues featured collection synchronization', :aggregate_failures do
|
||||
account = subject.call('alice', 'example.com', payload)
|
||||
|
||||
expect(account.featured_collection_url).to eq ''
|
||||
expect(ActivityPub::SynchronizeFeaturedCollectionWorker).to have_enqueued_sidekiq_job(account.id, { 'hashtag' => true, 'request_id' => anything, 'collection' => payload['featured'] })
|
||||
end
|
||||
end
|
||||
|
||||
context 'when account is not suspended' do
|
||||
subject { described_class.new.call(account.username, account.domain, payload) }
|
||||
|
||||
|
||||
@@ -23,19 +23,27 @@ module ProviderRequestHelper
|
||||
body = encode_body(body)
|
||||
headers = {}
|
||||
headers['content-digest'] = content_digest(body)
|
||||
request = Linzer.new_request(method, url, {}, headers)
|
||||
request = "Net::HTTP::#{method.to_s.classify}".constantize.new(URI(url), headers)
|
||||
key = private_key_for(provider)
|
||||
signature = sign(request, key, %w(@method @target-uri content-digest))
|
||||
headers.merge(signature.to_h)
|
||||
Linzer.sign!(request, key:, components: %w(@method @target-uri content-digest))
|
||||
signature_headers(request)
|
||||
end
|
||||
|
||||
def response_authentication_headers(provider, status, body)
|
||||
headers = {}
|
||||
headers['content-digest'] = content_digest(body)
|
||||
response = Linzer.new_response(body, status, headers)
|
||||
response = Net::HTTPResponse::CODE_TO_OBJ[status.to_s].new('1.1', status, Rack::Utils::HTTP_STATUS_CODES[status])
|
||||
response.body = body
|
||||
response['content-digest'] = content_digest(body)
|
||||
key = private_key_for(provider)
|
||||
signature = sign(response, key, %w(@status content-digest))
|
||||
headers.merge(signature.to_h)
|
||||
Linzer.sign!(response, key:, components: %w(@status content-digest))
|
||||
signature_headers(response)
|
||||
end
|
||||
|
||||
def signature_headers(operation)
|
||||
{
|
||||
'content-digest' => operation['content-digest'],
|
||||
'signature-input' => operation['signature-input'],
|
||||
'signature' => operation['signature'],
|
||||
}
|
||||
end
|
||||
|
||||
def private_key_for(provider)
|
||||
@@ -47,16 +55,7 @@ module ProviderRequestHelper
|
||||
key
|
||||
end
|
||||
|
||||
{
|
||||
id: provider.id.to_s,
|
||||
private_key: @cached_provider_keys[provider].private_to_pem,
|
||||
}
|
||||
end
|
||||
|
||||
def sign(request_or_response, key, components)
|
||||
message = Linzer::Message.new(request_or_response)
|
||||
linzer_key = Linzer.new_ed25519_key(key[:private_key], key[:id])
|
||||
Linzer.sign(linzer_key, message, components)
|
||||
Linzer.new_ed25519_key(@cached_provider_keys[provider].private_to_pem, provider.id.to_s)
|
||||
end
|
||||
|
||||
def encode_body(body)
|
||||
|
||||
Reference in New Issue
Block a user