Coverage for remote follows (#2694)
* Add coverage for create with empty acct value * Add coverage for create with webfinger failure * Add coverage for create with webfinger providing bad values * Add coverage for create when webfinger is good * Add coverage for session[:remote_follow] having data * Simplify how remote follow pulls acct from session * Remote follow behaves more like model * Move the discovery portions of remote follow out of controller * Check for suspended accounts
This commit is contained in:
		
				
					committed by
					
						
						Eugen Rochko
					
				
			
			
				
	
			
			
			
						parent
						
							7bffd16024
						
					
				
				
					commit
					a4859446ab
				
			@@ -4,34 +4,21 @@ class RemoteFollowController < ApplicationController
 | 
				
			|||||||
  layout 'public'
 | 
					  layout 'public'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before_action :set_account
 | 
					  before_action :set_account
 | 
				
			||||||
  before_action :check_account_suspension
 | 
					  before_action :gone, if: -> { @account.suspended? }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def new
 | 
					  def new
 | 
				
			||||||
    @remote_follow = RemoteFollow.new
 | 
					    @remote_follow = RemoteFollow.new(session_params)
 | 
				
			||||||
    @remote_follow.acct = session[:remote_follow] if session.key?(:remote_follow)
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create
 | 
					  def create
 | 
				
			||||||
    @remote_follow = RemoteFollow.new(resource_params)
 | 
					    @remote_follow = RemoteFollow.new(resource_params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if @remote_follow.valid?
 | 
					    if @remote_follow.valid?
 | 
				
			||||||
      resource          = Goldfinger.finger("acct:#{@remote_follow.acct}")
 | 
					 | 
				
			||||||
      redirect_url_link = resource&.link('http://ostatus.org/schema/1.0/subscribe')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      if redirect_url_link.nil? || redirect_url_link.template.nil?
 | 
					 | 
				
			||||||
        @remote_follow.errors.add(:acct, I18n.t('remote_follow.missing_resource'))
 | 
					 | 
				
			||||||
        render(:new) && return
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      session[:remote_follow] = @remote_follow.acct
 | 
					      session[:remote_follow] = @remote_follow.acct
 | 
				
			||||||
 | 
					      redirect_to @remote_follow.subscribe_address_for(@account)
 | 
				
			||||||
      redirect_to Addressable::Template.new(redirect_url_link.template).expand(uri: @account.to_webfinger_s).to_s
 | 
					 | 
				
			||||||
    else
 | 
					    else
 | 
				
			||||||
      render :new
 | 
					      render :new
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  rescue Goldfinger::Error
 | 
					 | 
				
			||||||
    @remote_follow.errors.add(:acct, I18n.t('remote_follow.missing_resource'))
 | 
					 | 
				
			||||||
    render :new
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  private
 | 
					  private
 | 
				
			||||||
@@ -40,11 +27,11 @@ class RemoteFollowController < ApplicationController
 | 
				
			|||||||
    params.require(:remote_follow).permit(:acct)
 | 
					    params.require(:remote_follow).permit(:acct)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def session_params
 | 
				
			||||||
 | 
					    { acct: session[:remote_follow] }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def set_account
 | 
					  def set_account
 | 
				
			||||||
    @account = Account.find_local!(params[:account_username])
 | 
					    @account = Account.find_local!(params[:account_username])
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					 | 
				
			||||||
  def check_account_suspension
 | 
					 | 
				
			||||||
    head 410 if @account.suspended?
 | 
					 | 
				
			||||||
  end
 | 
					 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,11 +3,47 @@
 | 
				
			|||||||
class RemoteFollow
 | 
					class RemoteFollow
 | 
				
			||||||
  include ActiveModel::Validations
 | 
					  include ActiveModel::Validations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  attr_accessor :acct
 | 
					  attr_accessor :acct, :addressable_template
 | 
				
			||||||
 | 
					 | 
				
			||||||
  validates :acct, presence: true
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def initialize(attrs = {})
 | 
					  def initialize(attrs = {})
 | 
				
			||||||
    @acct = attrs[:acct].strip unless attrs[:acct].nil?
 | 
					    @acct = attrs[:acct].strip unless attrs[:acct].nil?
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def valid?
 | 
				
			||||||
 | 
					    populate_template
 | 
				
			||||||
 | 
					    errors.empty?
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def subscribe_address_for(account)
 | 
				
			||||||
 | 
					    addressable_template.expand(uri: account.to_webfinger_s).to_s
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def populate_template
 | 
				
			||||||
 | 
					    if acct.blank? || redirect_url_link.nil? || redirect_url_link.template.nil?
 | 
				
			||||||
 | 
					      missing_resource_error
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					      @addressable_template = Addressable::Template.new(redirect_uri_template)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def redirect_uri_template
 | 
				
			||||||
 | 
					    redirect_url_link.template
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def redirect_url_link
 | 
				
			||||||
 | 
					    acct_resource&.link('http://ostatus.org/schema/1.0/subscribe')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def acct_resource
 | 
				
			||||||
 | 
					    @_acct_resource ||= Goldfinger.finger("acct:#{acct}")
 | 
				
			||||||
 | 
					  rescue Goldfinger::Error
 | 
				
			||||||
 | 
					    missing_resource_error
 | 
				
			||||||
 | 
					    nil
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def missing_resource_error
 | 
				
			||||||
 | 
					    errors.add(:acct, I18n.t('remote_follow.missing_resource'))
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,11 +6,105 @@ describe RemoteFollowController do
 | 
				
			|||||||
  render_views
 | 
					  render_views
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  describe '#new' do
 | 
					  describe '#new' do
 | 
				
			||||||
    it 'returns a success' do
 | 
					    it 'returns success when session is empty' do
 | 
				
			||||||
      account = Fabricate(:account)
 | 
					      account = Fabricate(:account)
 | 
				
			||||||
      get :new, params: { account_username: account.to_param }
 | 
					      get :new, params: { account_username: account.to_param }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(response).to have_http_status(:success)
 | 
					      expect(response).to have_http_status(:success)
 | 
				
			||||||
 | 
					      expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					      expect(assigns(:remote_follow).acct).to be_nil
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'populates the remote follow with session data when session exists' do
 | 
				
			||||||
 | 
					      session[:remote_follow] = 'user@example.com'
 | 
				
			||||||
 | 
					      account = Fabricate(:account)
 | 
				
			||||||
 | 
					      get :new, params: { account_username: account.to_param }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(response).to have_http_status(:success)
 | 
				
			||||||
 | 
					      expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					      expect(assigns(:remote_follow).acct).to eq 'user@example.com'
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe '#create' do
 | 
				
			||||||
 | 
					    before do
 | 
				
			||||||
 | 
					      @account = Fabricate(:account, username: 'test_user')
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'with a valid acct' do
 | 
				
			||||||
 | 
					      context 'when webfinger values are wrong' do
 | 
				
			||||||
 | 
					        it 'renders new when redirect url is nil' do
 | 
				
			||||||
 | 
					          resource_with_nil_link = double(link: nil)
 | 
				
			||||||
 | 
					          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_nil_link)
 | 
				
			||||||
 | 
					          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					          expect(response.body).to include(I18n.t('remote_follow.missing_resource'))
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'renders new when template is nil' do
 | 
				
			||||||
 | 
					          link_with_nil_template = double(template: nil)
 | 
				
			||||||
 | 
					          resource_with_link = double(link: link_with_nil_template)
 | 
				
			||||||
 | 
					          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)
 | 
				
			||||||
 | 
					          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					          expect(response.body).to include(I18n.t('remote_follow.missing_resource'))
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      context 'when webfinger values are good' do
 | 
				
			||||||
 | 
					        before do
 | 
				
			||||||
 | 
					          link_with_template = double(template: 'http://example.com/follow_me?acct={uri}')
 | 
				
			||||||
 | 
					          resource_with_link = double(link: link_with_template)
 | 
				
			||||||
 | 
					          allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_return(resource_with_link)
 | 
				
			||||||
 | 
					          post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'saves the session' do
 | 
				
			||||||
 | 
					          expect(session[:remote_follow]).to eq 'user@example.com'
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        it 'redirects to the remote location' do
 | 
				
			||||||
 | 
					          address = "http://example.com/follow_me?acct=acct%3Atest_user%40#{Rails.configuration.x.local_domain}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          expect(response).to redirect_to(address)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    context 'with an invalid acct' do
 | 
				
			||||||
 | 
					      it 'renders new when acct is missing' do
 | 
				
			||||||
 | 
					        post :create, params: { account_username: @account.to_param, remote_follow: { acct: '' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      it 'renders new with error when goldfinger fails' do
 | 
				
			||||||
 | 
					        allow(Goldfinger).to receive(:finger).with('acct:user@example.com').and_raise(Goldfinger::Error)
 | 
				
			||||||
 | 
					        post :create, params: { account_username: @account.to_param, remote_follow: { acct: 'user@example.com' } }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        expect(response).to render_template(:new)
 | 
				
			||||||
 | 
					        expect(response.body).to include(I18n.t('remote_follow.missing_resource'))
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  describe 'with a suspended account' do
 | 
				
			||||||
 | 
					    before do
 | 
				
			||||||
 | 
					      @account = Fabricate(:account, suspended: true)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns 410 gone on GET to #new' do
 | 
				
			||||||
 | 
					      get :new, params: { account_username: @account.to_param }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(response).to have_http_status(:gone)
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    it 'returns 410 gone on POST to #create' do
 | 
				
			||||||
 | 
					      post :create, params: { account_username: @account.to_param }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      expect(response).to have_http_status(:gone)
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user