Merge branch 'master' into glitch-soc/merge-upstream

Conflicts:
- app/controllers/application_controller.rb
- app/controllers/auth/confirmations_controller.rb
- app/controllers/auth/sessions_controller.rb
- app/controllers/settings/deletes_controller.rb
- app/controllers/settings/two_factor_authentication/recovery_codes_controller.rb
This commit is contained in:
Thibaut Girka
2019-07-23 10:17:06 +02:00
76 changed files with 662 additions and 590 deletions

View File

@@ -15,7 +15,7 @@ describe Api::BaseController do
end
end
describe 'Forgery protection' do
describe 'forgery protection' do
before do
routes.draw { post 'success' => 'api/base#success' }
end
@@ -27,7 +27,45 @@ describe Api::BaseController do
end
end
describe 'Error handling' do
describe 'non-functional accounts handling' do
let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) }
let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') }
controller do
before_action :require_user!
end
before do
routes.draw { post 'success' => 'api/base#success' }
allow(controller).to receive(:doorkeeper_token) { token }
end
it 'returns http forbidden for unconfirmed accounts' do
user.update(confirmed_at: nil)
post 'success'
expect(response).to have_http_status(403)
end
it 'returns http forbidden for pending accounts' do
user.update(approved: false)
post 'success'
expect(response).to have_http_status(403)
end
it 'returns http forbidden for disabled accounts' do
user.update(disabled: true)
post 'success'
expect(response).to have_http_status(403)
end
it 'returns http forbidden for suspended accounts' do
user.account.suspend!
post 'success'
expect(response).to have_http_status(403)
end
end
describe 'error handling' do
ERRORS_WITH_CODES = {
ActiveRecord::RecordInvalid => 422,
Mastodon::ValidationError => 422,

View File

@@ -191,10 +191,10 @@ describe ApplicationController, type: :controller do
expect(response).to have_http_status(200)
end
it 'returns http 403 if user who signed in is suspended' do
it 'redirects to account status page' do
sign_in(Fabricate(:user, account: Fabricate(:account, suspended: true)))
get 'success'
expect(response).to have_http_status(403)
expect(response).to redirect_to(edit_user_registration_path)
end
end

View File

@@ -50,45 +50,4 @@ describe Auth::ConfirmationsController, type: :controller do
end
end
end
describe 'GET #finish_signup' do
subject { get :finish_signup }
let(:user) { Fabricate(:user) }
before do
sign_in user, scope: :user
@request.env['devise.mapping'] = Devise.mappings[:user]
end
it 'renders finish_signup' do
is_expected.to render_template :finish_signup
expect(assigns(:user)).to have_attributes id: user.id
end
end
describe 'PATCH #finish_signup' do
subject { patch :finish_signup, params: { user: { email: email } } }
let(:user) { Fabricate(:user) }
before do
sign_in user, scope: :user
@request.env['devise.mapping'] = Devise.mappings[:user]
end
context 'when email is valid' do
let(:email) { 'new_' + user.email }
it 'redirects to root_path' do
is_expected.to redirect_to root_path
end
end
context 'when email is invalid' do
let(:email) { '' }
it 'renders finish_signup' do
is_expected.to render_template :finish_signup
end
end
end
end

View File

@@ -46,6 +46,15 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
post :update
expect(response).to have_http_status(200)
end
context 'when suspended' do
it 'returns http forbidden' do
request.env["devise.mapping"] = Devise.mappings[:user]
sign_in(Fabricate(:user, account_attributes: { username: 'test', suspended_at: Time.now.utc }), scope: :user)
post :update
expect(response).to have_http_status(403)
end
end
end
describe 'GET #new' do
@@ -94,9 +103,9 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678' } }
end
it 'redirects to login page' do
it 'redirects to setup' do
subject
expect(response).to redirect_to new_user_session_path
expect(response).to redirect_to auth_setup_path
end
it 'creates user' do
@@ -120,9 +129,9 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678' } }
end
it 'redirects to login page' do
it 'redirects to setup' do
subject
expect(response).to redirect_to new_user_session_path
expect(response).to redirect_to auth_setup_path
end
it 'creates user' do
@@ -148,9 +157,9 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', 'invite_code': invite.code } }
end
it 'redirects to login page' do
it 'redirects to setup' do
subject
expect(response).to redirect_to new_user_session_path
expect(response).to redirect_to auth_setup_path
end
it 'creates user' do
@@ -176,9 +185,9 @@ RSpec.describe Auth::RegistrationsController, type: :controller do
post :create, params: { user: { account_attributes: { username: 'test' }, email: 'test@example.com', password: '12345678', password_confirmation: '12345678', 'invite_code': invite.code } }
end
it 'redirects to login page' do
it 'redirects to setup' do
subject
expect(response).to redirect_to new_user_session_path
expect(response).to redirect_to auth_setup_path
end
it 'creates user' do

View File

@@ -160,8 +160,8 @@ RSpec.describe Auth::SessionsController, type: :controller do
let(:unconfirmed_user) { user.tap { |u| u.update!(confirmed_at: nil) } }
let(:accept_language) { 'fr' }
it 'shows a translated login error' do
expect(flash[:alert]).to eq(I18n.t('devise.failure.unconfirmed', locale: accept_language))
it 'redirects to home' do
expect(response).to redirect_to(root_path)
end
end

View File

@@ -7,16 +7,10 @@ describe ApplicationController, type: :controller do
include Localized
def success
head 200
render plain: I18n.locale, status: 200
end
end
around do |example|
current_locale = I18n.locale
example.run
I18n.locale = current_locale
end
before do
routes.draw { get 'success' => 'anonymous#success' }
end
@@ -25,19 +19,19 @@ describe ApplicationController, type: :controller do
it 'sets available and preferred language' do
request.headers['Accept-Language'] = 'ca-ES, fa'
get 'success'
expect(I18n.locale).to eq :fa
expect(response.body).to eq 'fa'
end
it 'sets available and compatible language if none of available languages are preferred' do
request.headers['Accept-Language'] = 'fa-IR'
get 'success'
expect(I18n.locale).to eq :fa
expect(response.body).to eq 'fa'
end
it 'sets default locale if none of available languages are compatible' do
request.headers['Accept-Language'] = ''
get 'success'
expect(I18n.locale).to eq :en
expect(response.body).to eq 'en'
end
end
@@ -48,7 +42,7 @@ describe ApplicationController, type: :controller do
sign_in(user)
get 'success'
expect(I18n.locale).to eq :ca
expect(response.body).to eq 'ca'
end
end

View File

@@ -15,6 +15,15 @@ describe Settings::DeletesController do
get :show
expect(response).to have_http_status(200)
end
context 'when suspended' do
let(:user) { Fabricate(:user, account_attributes: { username: 'alice', suspended_at: Time.now.utc }) }
it 'returns http forbidden' do
get :show
expect(response).to have_http_status(403)
end
end
end
context 'when not signed in' do
@@ -49,6 +58,14 @@ describe Settings::DeletesController do
it 'marks account as suspended' do
expect(user.account.reload).to be_suspended
end
context 'when suspended' do
let(:user) { Fabricate(:user, account_attributes: { username: 'alice', suspended_at: Time.now.utc }) }
it 'returns http forbidden' do
expect(response).to have_http_status(403)
end
end
end
context 'with incorrect password' do

View File

@@ -1,7 +0,0 @@
Fabricator(:subscription) do
account
callback_url "http://example.com/callback"
secret "foobar"
expires_at "2016-11-28 11:30:07"
confirmed false
end

View File

@@ -31,12 +31,12 @@ feature "Log in" do
context do
given(:confirmed_at) { nil }
scenario "A unconfirmed user is not able to log in" do
scenario "A unconfirmed user is able to log in" do
fill_in "user_email", with: email
fill_in "user_password", with: password
click_on I18n.t('auth.login')
is_expected.to have_css(".flash-message", text: failure_message("unconfirmed"))
is_expected.to have_css("div.admin-wrapper")
end
end

View File

@@ -261,7 +261,7 @@ RSpec.describe Formatter do
let(:text) { ':coolcat: Beep boop' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/<img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
end
@@ -330,7 +330,7 @@ RSpec.describe Formatter do
let(:text) { ':coolcat: Beep boop' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/<p><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -338,7 +338,7 @@ RSpec.describe Formatter do
let(:text) { 'Beep :coolcat: boop' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/Beep <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -354,7 +354,7 @@ RSpec.describe Formatter do
let(:text) { 'Beep boop :coolcat:' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/boop <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/boop <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
end
@@ -377,7 +377,7 @@ RSpec.describe Formatter do
let(:text) { '<p>:coolcat: Beep boop<br />' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/<p><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -385,7 +385,7 @@ RSpec.describe Formatter do
let(:text) { '<p>Beep :coolcat: boop</p>' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/Beep <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -401,7 +401,7 @@ RSpec.describe Formatter do
let(:text) { '<p>Beep boop<br />:coolcat:</p>' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/<br><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<br><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
end
@@ -500,7 +500,7 @@ RSpec.describe Formatter do
let(:text) { ':coolcat: Beep boop' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/<p><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -508,7 +508,7 @@ RSpec.describe Formatter do
let(:text) { 'Beep :coolcat: boop' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/Beep <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -524,7 +524,7 @@ RSpec.describe Formatter do
let(:text) { 'Beep boop :coolcat:' }
it 'converts the shortcode to an image tag' do
is_expected.to match(/boop <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/boop <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
end
@@ -551,7 +551,7 @@ RSpec.describe Formatter do
let(:text) { '<p>:coolcat: Beep boop<br />' }
it 'converts shortcode to image tag' do
is_expected.to match(/<p><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<p><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -559,7 +559,7 @@ RSpec.describe Formatter do
let(:text) { '<p>Beep :coolcat: boop</p>' }
it 'converts shortcode to image tag' do
is_expected.to match(/Beep <img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/Beep <img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
@@ -575,7 +575,7 @@ RSpec.describe Formatter do
let(:text) { '<p>Beep boop<br />:coolcat:</p>' }
it 'converts shortcode to image tag' do
is_expected.to match(/<br><img draggable="false" class="emojione" alt=":coolcat:"/)
is_expected.to match(/<br><img draggable="false" class="emojione custom-emoji" alt=":coolcat:"/)
end
end
end

View File

@@ -1,67 +0,0 @@
require 'rails_helper'
RSpec.describe Subscription, type: :model do
let(:alice) { Fabricate(:account, username: 'alice') }
subject { Fabricate(:subscription, account: alice) }
describe '#expired?' do
it 'return true when expires_at is past' do
subject.expires_at = 2.days.ago
expect(subject.expired?).to be true
end
it 'return false when expires_at is future' do
subject.expires_at = 2.days.from_now
expect(subject.expired?).to be false
end
end
describe 'lease_seconds' do
it 'returns the time remaining until expiration' do
datetime = 1.day.from_now
subscription = Subscription.new(expires_at: datetime)
travel_to(datetime - 12.hours) do
expect(subscription.lease_seconds).to eq(12.hours)
end
end
end
describe 'lease_seconds=' do
it 'sets expires_at to min expiration when small value is provided' do
subscription = Subscription.new
datetime = 1.day.from_now
too_low = Subscription::MIN_EXPIRATION - 1000
travel_to(datetime) do
subscription.lease_seconds = too_low
end
expected = datetime + Subscription::MIN_EXPIRATION.seconds
expect(subscription.expires_at).to be_within(1.0).of(expected)
end
it 'sets expires_at to value when valid value is provided' do
subscription = Subscription.new
datetime = 1.day.from_now
valid = Subscription::MIN_EXPIRATION + 1000
travel_to(datetime) do
subscription.lease_seconds = valid
end
expected = datetime + valid.seconds
expect(subscription.expires_at).to be_within(1.0).of(expected)
end
it 'sets expires_at to max expiration when large value is provided' do
subscription = Subscription.new
datetime = 1.day.from_now
too_high = Subscription::MAX_EXPIRATION + 1000
travel_to(datetime) do
subscription.lease_seconds = too_high
end
expected = datetime + Subscription::MAX_EXPIRATION.seconds
expect(subscription.expires_at).to be_within(1.0).of(expected)
end
end
end

View File

@@ -506,7 +506,7 @@ RSpec.describe User, type: :model do
context 'when user is not confirmed' do
let(:confirmed_at) { nil }
it { is_expected.to be false }
it { is_expected.to be true }
end
end
@@ -522,7 +522,7 @@ RSpec.describe User, type: :model do
context 'when user is not confirmed' do
let(:confirmed_at) { nil }
it { is_expected.to be false }
it { is_expected.to be true }
end
end
end

View File

@@ -1,24 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
require 'pundit/rspec'
RSpec.describe SubscriptionPolicy do
let(:subject) { described_class }
let(:admin) { Fabricate(:user, admin: true).account }
let(:john) { Fabricate(:user).account }
permissions :index? do
context 'admin?' do
it 'permits' do
expect(subject).to permit(admin, Subscription)
end
end
context '!admin?' do
it 'denies' do
expect(subject).to_not permit(john, Subscription)
end
end
end
end

View File

@@ -14,11 +14,8 @@ RSpec.describe BatchedRemoveStatusService, type: :service do
before do
allow(Redis.current).to receive_messages(publish: nil)
stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
jeff.user.update(current_sign_in_at: Time.zone.now)
jeff.follow!(alice)
hank.follow!(alice)

View File

@@ -10,12 +10,9 @@ RSpec.describe RemoveStatusService, type: :service do
let!(:bill) { Fabricate(:account, username: 'bill', protocol: :activitypub, domain: 'example2.com', inbox_url: 'http://example2.com/inbox') }
before do
stub_request(:post, 'http://example.com/push').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/salmon').to_return(status: 200, body: '', headers: {})
stub_request(:post, 'http://example.com/inbox').to_return(status: 200)
stub_request(:post, 'http://example2.com/inbox').to_return(status: 200)
Fabricate(:subscription, account: alice, callback_url: 'http://example.com/push', confirmed: true, expires_at: 30.days.from_now)
jeff.follow!(alice)
hank.follow!(alice)

View File

@@ -18,7 +18,6 @@ RSpec.describe SuspendAccountService, type: :service do
let!(:favourite) { Fabricate(:favourite, account: account) }
let!(:active_relationship) { Fabricate(:follow, account: account) }
let!(:passive_relationship) { Fabricate(:follow, target_account: account) }
let!(:subscription) { Fabricate(:subscription, account: account) }
let!(:remote_alice) { Fabricate(:account, inbox_url: 'https://alice.com/inbox', protocol: :activitypub) }
let!(:remote_bob) { Fabricate(:account, inbox_url: 'https://bob.com/inbox', protocol: :activitypub) }
@@ -31,9 +30,8 @@ RSpec.describe SuspendAccountService, type: :service do
account.favourites,
account.active_relationships,
account.passive_relationships,
account.subscriptions
].map(&:count)
}.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0])
}.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
end
it 'sends a delete actor activity to all known inboxes' do
@@ -62,7 +60,6 @@ RSpec.describe SuspendAccountService, type: :service do
let!(:favourite) { Fabricate(:favourite, account: remote_bob) }
let!(:active_relationship) { Fabricate(:follow, account: remote_bob, target_account: account) }
let!(:passive_relationship) { Fabricate(:follow, target_account: remote_bob) }
let!(:subscription) { Fabricate(:subscription, account: remote_bob) }
it 'deletes associated records' do
is_expected.to change {
@@ -73,9 +70,8 @@ RSpec.describe SuspendAccountService, type: :service do
remote_bob.favourites,
remote_bob.active_relationships,
remote_bob.passive_relationships,
remote_bob.subscriptions
].map(&:count)
}.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0])
}.from([1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0])
end
it 'sends a reject follow to follwer inboxes' do