1
0
Fork 0
forked from gitea/nas

Merge remote-tracking branch 'parent/main' into upstream-20230105

This commit is contained in:
KMY 2024-01-05 10:01:36 +09:00
commit a0a3d1b101
65 changed files with 1008 additions and 453 deletions

View file

@ -12,13 +12,14 @@ RSpec.describe Admin::EmailDomainBlocksController do
describe 'GET #index' do
around do |example|
default_per_page = EmailDomainBlock.default_per_page
EmailDomainBlock.paginates_per 1
EmailDomainBlock.paginates_per 2
example.run
EmailDomainBlock.paginates_per default_per_page
end
it 'returns http success' do
2.times { Fabricate(:email_domain_block) }
Fabricate(:email_domain_block, allow_with_approval: true)
get :index, params: { page: 2 }
expect(response).to have_http_status(200)
end

View file

@ -135,6 +135,25 @@ RSpec.describe Auth::RegistrationsController do
end
end
context 'when user has an email address requiring approval' do
subject do
Setting.registrations_mode = 'open'
Fabricate(:email_domain_block, allow_with_approval: true, domain: 'example.com')
request.headers['Accept-Language'] = accept_language
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', agreement: 'true' } }
end
it 'creates unapproved user and redirects to setup' do
subject
expect(response).to redirect_to auth_setup_path
user = User.find_by(email: 'test@example.com')
expect(user).to_not be_nil
expect(user.locale).to eq(accept_language)
expect(user.approved).to be(false)
end
end
context 'with Approval-based registrations without invite' do
subject do
Setting.registrations_mode = 'approved'

View file

@ -22,7 +22,7 @@ describe 'Admin::Accounts' do
context 'without selecting any accounts' do
it 'displays a notice about account selection' do
click_button button_for_suspend
click_on button_for_suspend
expect(page).to have_content(selection_error_text)
end
@ -32,7 +32,7 @@ describe 'Admin::Accounts' do
it 'suspends the account' do
batch_checkbox_for(approved_user_account).check
click_button button_for_suspend
click_on button_for_suspend
expect(approved_user_account.reload).to be_suspended
end
@ -42,7 +42,7 @@ describe 'Admin::Accounts' do
it 'approves the account user' do
batch_checkbox_for(unapproved_user_account).check
click_button button_for_approve
click_on button_for_approve
expect(unapproved_user_account.reload.user).to be_approved
end
@ -52,7 +52,7 @@ describe 'Admin::Accounts' do
it 'rejects and removes the account' do
batch_checkbox_for(unapproved_user_account).check
click_button button_for_reject
click_on button_for_reject
expect { unapproved_user_account.reload }.to raise_error(ActiveRecord::RecordNotFound)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::CustomEmojis' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_enable
click_on button_for_enable
expect(page).to have_content(selection_error_text)
end

View file

@ -14,7 +14,7 @@ describe 'blocking domains through the moderation interface' do
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.silence'), from: 'domain_block_severity'
click_button I18n.t('admin.domain_blocks.new.create')
click_on I18n.t('admin.domain_blocks.new.create')
expect(DomainBlock.exists?(domain: 'example.com', severity: 'silence')).to be true
expect(DomainBlockWorker).to have_received(:perform_async)
@ -27,14 +27,14 @@ describe 'blocking domains through the moderation interface' do
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
click_button I18n.t('admin.domain_blocks.new.create')
click_on I18n.t('admin.domain_blocks.new.create')
# It doesn't immediately block but presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
expect(DomainBlockWorker).to_not have_received(:perform_async)
# Confirming creates a block
click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(DomainBlock.exists?(domain: 'example.com', severity: 'suspend')).to be true
expect(DomainBlockWorker).to have_received(:perform_async)
@ -49,14 +49,14 @@ describe 'blocking domains through the moderation interface' do
fill_in 'domain_block_domain', with: 'example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
click_button I18n.t('admin.domain_blocks.new.create')
click_on I18n.t('admin.domain_blocks.new.create')
# It doesn't immediately block but presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
expect(DomainBlockWorker).to_not have_received(:perform_async)
# Confirming updates the block
click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(domain_block.reload.severity).to eq 'suspend'
expect(DomainBlockWorker).to have_received(:perform_async)
@ -71,14 +71,14 @@ describe 'blocking domains through the moderation interface' do
fill_in 'domain_block_domain', with: 'subdomain.example.com'
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
click_button I18n.t('admin.domain_blocks.new.create')
click_on I18n.t('admin.domain_blocks.new.create')
# It doesn't immediately block but presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'subdomain.example.com'))
expect(DomainBlockWorker).to_not have_received(:perform_async)
# Confirming creates the block
click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(DomainBlock.where(domain: 'subdomain.example.com', severity: 'suspend')).to exist
expect(DomainBlockWorker).to have_received(:perform_async)
@ -96,14 +96,14 @@ describe 'blocking domains through the moderation interface' do
visit edit_admin_domain_block_path(domain_block)
select I18n.t('admin.domain_blocks.new.severity.suspend'), from: 'domain_block_severity'
click_button I18n.t('generic.save_changes')
click_on I18n.t('generic.save_changes')
# It doesn't immediately block but presents a confirmation screen
expect(page).to have_title(I18n.t('admin.domain_blocks.confirm_suspension.title', domain: 'example.com'))
expect(DomainBlockWorker).to_not have_received(:perform_async)
# Confirming updates the block
click_button I18n.t('admin.domain_blocks.confirm_suspension.confirm')
click_on I18n.t('admin.domain_blocks.confirm_suspension.confirm')
expect(DomainBlockWorker).to have_received(:perform_async)
expect(domain_block.reload.severity).to eq 'suspend'

View file

@ -16,7 +16,7 @@ describe 'Admin::EmailDomainBlocks' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_delete
click_on button_for_delete
expect(page).to have_content(selection_error_text)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::IpBlocks' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_delete
click_on button_for_delete
expect(page).to have_content(selection_error_text)
end

View file

@ -11,13 +11,13 @@ describe 'finding software updates through the admin interface' do
it 'shows a link to the software updates page, which links to release notes' do
visit settings_profile_path
click_link I18n.t('admin.critical_update_pending')
click_on I18n.t('admin.critical_update_pending')
expect(page).to have_title(I18n.t('admin.software_updates.title'))
expect(page).to have_content('99.99.99')
click_link I18n.t('admin.software_updates.release_notes')
click_on I18n.t('admin.software_updates.release_notes')
expect(page).to have_current_path('https://github.com/mastodon/mastodon/releases/v99', url: true)
end
end

View file

@ -17,7 +17,7 @@ describe 'Admin::Statuses' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_report
click_on button_for_report
expect(page).to have_content(selection_error_text)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::Trends::Links::PreviewCardProviders' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_allow
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::Trends::Links' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_allow
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::Trends::Statuses' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_allow
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end

View file

@ -16,7 +16,7 @@ describe 'Admin::Trends::Tags' do
context 'without selecting any records' do
it 'displays a notice about selection' do
click_button button_for_allow
click_on button_for_allow
expect(page).to have_content(selection_error_text)
end

View file

@ -23,7 +23,7 @@ describe 'email confirmation flow when captcha is enabled' do
expect(user.reload.confirmed?).to be false
# It redirects to app and confirms user
click_button I18n.t('challenge.confirm')
click_on I18n.t('challenge.confirm')
expect(user.reload.confirmed?).to be true
expect(page).to have_current_path(/\A#{client_app.confirmation_redirect_uri}/, url: true)

View file

@ -19,7 +19,7 @@ describe 'Log in' do
it 'A valid email and password user is able to log in' do
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(subject).to have_css('div.app-holder')
end
@ -27,7 +27,7 @@ describe 'Log in' do
it 'A invalid email and password user is not able to log in' do
fill_in 'user_email', with: 'invalid_email'
fill_in 'user_password', with: 'invalid_password'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(subject).to have_css('.flash-message', text: failure_message('invalid'))
end
@ -38,7 +38,7 @@ describe 'Log in' do
it 'A unconfirmed user is able to log in' do
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(subject).to have_css('div.admin-wrapper')
end

View file

@ -20,7 +20,7 @@ describe 'Using OAuth from an external app' do
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@ -35,7 +35,7 @@ describe 'Using OAuth from an external app' do
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.deny'))
# Upon denying, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.deny')
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account
@ -63,17 +63,17 @@ describe 'Using OAuth from an external app' do
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to an authorization page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@ -90,17 +90,17 @@ describe 'Using OAuth from an external app' do
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to an authorization page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon denying, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.deny')
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account
@ -120,27 +120,27 @@ describe 'Using OAuth from an external app' do
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to a two-factor authentication page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in an incorrect two-factor authentication code presents the form again
fill_in 'user_otp_attempt', with: 'wrong'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in the correct TOTP code redirects to an app authorization page
fill_in 'user_otp_attempt', with: user.current_otp
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon authorizing, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.authorize')
click_on I18n.t('doorkeeper.authorizations.buttons.authorize')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It grants the app access to the account
@ -157,27 +157,27 @@ describe 'Using OAuth from an external app' do
# Failing to log-in presents the form again
fill_in 'user_email', with: email
fill_in 'user_password', with: 'wrong password'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('auth.login'))
# Logging in redirects to a two-factor authentication page
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in an incorrect two-factor authentication code presents the form again
fill_in 'user_otp_attempt', with: 'wrong'
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('simple_form.hints.sessions.otp'))
# Filling in the correct TOTP code redirects to an app authorization page
fill_in 'user_otp_attempt', with: user.current_otp
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
expect(page).to have_content(I18n.t('doorkeeper.authorizations.buttons.authorize'))
# Upon denying, it redirects to the apps' callback URL
click_button I18n.t('doorkeeper.authorizations.buttons.deny')
click_on I18n.t('doorkeeper.authorizations.buttons.deny')
expect(page).to have_current_path(/\A#{client_app.redirect_uri}/, url: true)
# It does not grant the app access to the account

View file

@ -20,4 +20,157 @@ describe Mastodon::CLI::Main do
.to output_results(Mastodon::Version.to_s)
end
end
describe '#self_destruct' do
let(:action) { :self_destruct }
context 'with self destruct mode enabled' do
before do
allow(SelfDestructHelper).to receive(:self_destruct?).and_return(true)
end
context 'with pending accounts' do
before { Fabricate(:account) }
it 'reports about pending accounts' do
expect { subject }
.to output_results(
'already enabled',
'still pending deletion'
)
.and raise_error(SystemExit)
end
end
context 'with sidekiq notices being processed' do
before do
Account.delete_all
stats_double = instance_double(Sidekiq::Stats, enqueued: 5)
allow(Sidekiq::Stats).to receive(:new).and_return(stats_double)
end
it 'reports about notices' do
expect { subject }
.to output_results(
'already enabled',
'notices are still being'
)
.and raise_error(SystemExit)
end
end
context 'with sidekiq failed deliveries' do
before do
Account.delete_all
stats_double = instance_double(Sidekiq::Stats, enqueued: 0, retry_size: 10)
allow(Sidekiq::Stats).to receive(:new).and_return(stats_double)
end
it 'reports about notices' do
expect { subject }
.to output_results(
'already enabled',
'some have failed and are scheduled'
)
.and raise_error(SystemExit)
end
end
context 'with self descruct mode ready' do
before do
Account.delete_all
stats_double = instance_double(Sidekiq::Stats, enqueued: 0, retry_size: 0)
allow(Sidekiq::Stats).to receive(:new).and_return(stats_double)
end
it 'reports about notices' do
expect { subject }
.to output_results(
'already enabled',
'can safely delete all data'
)
.and raise_error(SystemExit)
end
end
end
context 'with self destruct mode disabled' do
before do
allow(SelfDestructHelper).to receive(:self_destruct?).and_return(false)
end
context 'with an incorrect response to hostname' do
before do
answer_hostname_incorrectly
end
it 'exits silently' do
expect { subject }
.to raise_error(SystemExit)
end
end
context 'with a correct response to hostname but no to proceed' do
before do
answer_hostname_correctly
decline_proceed
end
it 'passes first step but stops before instructions' do
expect { subject }
.to output_results('operation WILL NOT')
.and raise_error(SystemExit)
end
end
context 'with a correct response to hostname and yes to proceed' do
before do
answer_hostname_correctly
accept_proceed
end
it 'instructs to set the appropriate environment variable' do
expect { subject }
.to output_results(
'operation WILL NOT',
'the following variable'
)
end
end
private
def answer_hostname_incorrectly
allow(cli.shell)
.to receive(:ask)
.with('Type in the domain of the server to confirm:')
.and_return('wrong.host')
.once
end
def answer_hostname_correctly
allow(cli.shell)
.to receive(:ask)
.with('Type in the domain of the server to confirm:')
.and_return(Rails.configuration.x.local_domain)
.once
end
def decline_proceed
allow(cli.shell)
.to receive(:no?)
.with('Are you sure you want to proceed?')
.and_return(true)
.once
end
def accept_proceed
allow(cli.shell)
.to receive(:no?)
.with('Are you sure you want to proceed?')
.and_return(false)
.once
end
end
end
end

View file

@ -184,4 +184,58 @@ describe Mastodon::CLI::Media do
end
end
end
describe '#remove_orphans' do
let(:action) { :remove_orphans }
before do
FileUtils.mkdir_p Rails.public_path.join('system')
end
context 'without any options' do
it 'runs without error' do
expect { subject }
.to output_results('Removed', 'orphans (approx')
end
end
context 'when in azure mode' do
before do
allow(Paperclip::Attachment).to receive(:default_options).and_return(storage: :azure)
end
it 'warns about usage and exits' do
expect { subject }
.to output_results('azure storage driver is not supported')
.and raise_error(SystemExit)
end
end
context 'when in fog mode' do
before do
allow(Paperclip::Attachment).to receive(:default_options).and_return(storage: :fog)
end
it 'warns about usage and exits' do
expect { subject }
.to output_results('fog storage driver is not supported')
.and raise_error(SystemExit)
end
end
context 'when in filesystem mode' do
before do
allow(File).to receive(:delete).and_return(true)
media_attachment.delete
end
let(:media_attachment) { Fabricate(:media_attachment) }
it 'removes the unlinked files' do
expect { subject }
.to output_results('Removed', 'orphans (approx')
expect(File).to have_received(:delete).with(media_attachment.file.path)
end
end
end
end

View file

@ -33,11 +33,13 @@ describe RequestPool do
subject
threads = Array.new(20) do |_i|
threads = Array.new(3) do
Thread.new do
20.times do
2.times do
subject.with('http://example.com') do |http_client|
http_client.get('/').flush
# Nudge scheduler to yield and exercise the full pool
sleep(0)
end
end
end

View file

@ -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' data: blob: https://cb6e6126.ngrok.io ws://localhost:4000",
"connect-src 'self' data: blob: https://cb6e6126.ngrok.io ws://cb6e6126.ngrok.io:4000",
"script-src 'self' https://cb6e6126.ngrok.io 'wasm-unsafe-eval'"
)
end

View file

@ -94,6 +94,72 @@ describe 'signature verification concern' do
end
end
context 'with a valid signature on a GET request that has a query string' do
let(:signature_header) do
'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="SDMa4r/DQYMXYxVgYO2yEqGWWUXugKjVuz0I8dniQAk+aunzBaF2aPu+4grBfawAshlx1Xytl8lhb0H2MllEz16/tKY7rUrb70MK0w8ohXgpb0qs3YvQgdj4X24L1x2MnkFfKHR/J+7TBlnivq0HZqXm8EIkPWLv+eQxu8fbowLwHIVvRd/3t6FzvcfsE0UZKkoMEX02542MhwSif6cu7Ec/clsY9qgKahb9JVGOGS1op9Lvg/9y1mc8KCgD83U5IxVygYeYXaVQ6gixA9NgZiTCwEWzHM5ELm7w5hpdLFYxYOHg/3G3fiqJzpzNQAcCD4S4JxfE7hMI0IzVlNLT6A=="' # rubocop:disable Layout/LineLength
end
it 'successfuly verifies signature', :aggregate_failures do
expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success?foo=42', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' })
get '/activitypub/success?foo=42', headers: {
'Host' => 'www.example.com',
'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT',
'Signature' => signature_header,
}
expect(response).to have_http_status(200)
expect(body_as_json).to match(
signed_request: true,
signature_actor_id: actor.id.to_s
)
end
end
context 'when the query string is missing from the signature verification (compatibility quirk)' do
let(:signature_header) do
'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="Z8ilar3J7bOwqZkMp7sL8sRs4B1FT+UorbmvWoE+A5UeoOJ3KBcUmbsh+k3wQwbP5gMNUrra9rEWabpasZGphLsbDxfbsWL3Cf0PllAc7c1c7AFEwnewtExI83/qqgEkfWc2z7UDutXc2NfgAx89Ox8DXU/fA2GG0jILjB6UpFyNugkY9rg6oI31UnvfVi3R7sr3/x8Ea3I9thPvqI2byF6cojknSpDAwYzeKdngX3TAQEGzFHz3SDWwyp3jeMWfwvVVbM38FxhvAnSumw7YwWW4L7M7h4M68isLimoT3yfCn2ucBVL5Dz8koBpYf/40w7QidClAwCafZQFC29yDOg=="' # rubocop:disable Layout/LineLength
end
it 'successfuly verifies signature', :aggregate_failures do
expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' })
get '/activitypub/success?foo=42', headers: {
'Host' => 'www.example.com',
'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT',
'Signature' => signature_header,
}
expect(response).to have_http_status(200)
expect(body_as_json).to match(
signed_request: true,
signature_actor_id: actor.id.to_s
)
end
end
context 'with mismatching query string' do
let(:signature_header) do
'keyId="https://remote.domain/users/bob#main-key",algorithm="rsa-sha256",headers="date host (request-target)",signature="SDMa4r/DQYMXYxVgYO2yEqGWWUXugKjVuz0I8dniQAk+aunzBaF2aPu+4grBfawAshlx1Xytl8lhb0H2MllEz16/tKY7rUrb70MK0w8ohXgpb0qs3YvQgdj4X24L1x2MnkFfKHR/J+7TBlnivq0HZqXm8EIkPWLv+eQxu8fbowLwHIVvRd/3t6FzvcfsE0UZKkoMEX02542MhwSif6cu7Ec/clsY9qgKahb9JVGOGS1op9Lvg/9y1mc8KCgD83U5IxVygYeYXaVQ6gixA9NgZiTCwEWzHM5ELm7w5hpdLFYxYOHg/3G3fiqJzpzNQAcCD4S4JxfE7hMI0IzVlNLT6A=="' # rubocop:disable Layout/LineLength
end
it 'fails to verify signature', :aggregate_failures do
expect(signature_header).to eq build_signature_string(actor_keypair, 'https://remote.domain/users/bob#main-key', 'get /activitypub/success?foo=42', { 'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT', 'Host' => 'www.example.com' })
get '/activitypub/success?foo=43', headers: {
'Host' => 'www.example.com',
'Date' => 'Wed, 20 Dec 2023 10:00:00 GMT',
'Signature' => signature_header,
}
expect(body_as_json).to match(
signed_request: true,
signature_actor_id: nil,
error: anything
)
end
end
context 'with a mismatching path' do
it 'fails to verify signature', :aggregate_failures do
get '/activitypub/alternative-path', headers: {

View file

@ -27,6 +27,27 @@ RSpec.describe AppSignUpService, type: :service do
end
end
context 'when the email address requires approval' do
before do
Setting.registrations_mode = 'open'
Fabricate(:email_domain_block, allow_with_approval: true, domain: 'email.com')
end
it 'creates an unapproved user', :aggregate_failures do
access_token = subject.call(app, remote_ip, params)
expect(access_token).to_not be_nil
expect(access_token.scopes.to_s).to eq 'read write'
user = User.find_by(id: access_token.resource_owner_id)
expect(user).to_not be_nil
expect(user.confirmed?).to be false
expect(user.approved?).to be false
expect(user.account).to_not be_nil
expect(user.invite_request).to be_nil
end
end
context 'when registrations are closed' do
before do
Setting.registrations_mode = 'none'

View file

@ -18,7 +18,7 @@ module ProfileStories
visit new_user_session_path
fill_in 'user_email', with: email
fill_in 'user_password', with: password
click_button I18n.t('auth.login')
click_on I18n.t('auth.login')
end
def with_alice_as_local_user

View file

@ -24,7 +24,7 @@ describe 'NewStatuses' do
within('.compose-form') do
fill_in "What's on your mind?", with: status_text
click_button 'Publish!'
click_on 'Publish!'
end
expect(subject).to have_css('.status__content__text', text: status_text)
@ -37,7 +37,7 @@ describe 'NewStatuses' do
within('.compose-form') do
fill_in "What's on your mind?", with: status_text
click_button 'Publish!'
click_on 'Publish!'
end
expect(subject).to have_css('.status__content__text', text: status_text)