Add ability to block sign-ups from IP (#19037)
This commit is contained in:
		
							parent
							
								
									e213af736f
								
							
						
					
					
						commit
						b2e1224baa
					
				
					 5 changed files with 64 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -82,7 +82,7 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		|||
  end
 | 
			
		||||
 | 
			
		||||
  def check_enabled_registrations
 | 
			
		||||
    redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations?
 | 
			
		||||
    redirect_to root_path if single_user_mode? || omniauth_only? || !allowed_registrations? || ip_blocked?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def allowed_registrations?
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +93,10 @@ class Auth::RegistrationsController < Devise::RegistrationsController
 | 
			
		|||
    ENV['OMNIAUTH_ONLY'] == 'true'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ip_blocked?
 | 
			
		||||
    IpBlock.where(severity: :sign_up_block).where('ip >>= ?', request.remote_ip.to_s).exists?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invite_code
 | 
			
		||||
    if params[:user]
 | 
			
		||||
      params[:user][:invite_code]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,7 @@ class IpBlock < ApplicationRecord
 | 
			
		|||
 | 
			
		||||
  enum severity: {
 | 
			
		||||
    sign_up_requires_approval: 5000,
 | 
			
		||||
    sign_up_block: 5500,
 | 
			
		||||
    no_access: 9999,
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,23 +2,67 @@
 | 
			
		|||
 | 
			
		||||
class AppSignUpService < BaseService
 | 
			
		||||
  def call(app, remote_ip, params)
 | 
			
		||||
    return unless allowed_registrations?
 | 
			
		||||
    @app       = app
 | 
			
		||||
    @remote_ip = remote_ip
 | 
			
		||||
    @params    = params
 | 
			
		||||
 | 
			
		||||
    user_params           = params.slice(:email, :password, :agreement, :locale)
 | 
			
		||||
    account_params        = params.slice(:username)
 | 
			
		||||
    invite_request_params = { text: params[:reason] }
 | 
			
		||||
    user                  = User.create!(user_params.merge(created_by_application: app, sign_up_ip: remote_ip, password_confirmation: user_params[:password], account_attributes: account_params, invite_request_attributes: invite_request_params))
 | 
			
		||||
    raise Mastodon::NotPermittedError unless allowed_registrations?
 | 
			
		||||
 | 
			
		||||
    Doorkeeper::AccessToken.create!(application: app,
 | 
			
		||||
                                    resource_owner_id: user.id,
 | 
			
		||||
                                    scopes: app.scopes,
 | 
			
		||||
                                    expires_in: Doorkeeper.configuration.access_token_expires_in,
 | 
			
		||||
                                    use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?)
 | 
			
		||||
    ApplicationRecord.transaction do
 | 
			
		||||
      create_user!
 | 
			
		||||
      create_access_token!
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    @access_token
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  private
 | 
			
		||||
 | 
			
		||||
  def create_user!
 | 
			
		||||
    @user = User.create!(
 | 
			
		||||
      user_params.merge(created_by_application: @app, sign_up_ip: @remote_ip, password_confirmation: user_params[:password], account_attributes: account_params, invite_request_attributes: invite_request_params)
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def create_access_token!
 | 
			
		||||
    @access_token = Doorkeeper::AccessToken.create!(
 | 
			
		||||
      application: @app,
 | 
			
		||||
      resource_owner_id: @user.id,
 | 
			
		||||
      scopes: @app.scopes,
 | 
			
		||||
      expires_in: Doorkeeper.configuration.access_token_expires_in,
 | 
			
		||||
      use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
 | 
			
		||||
    )
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def user_params
 | 
			
		||||
    @params.slice(:email, :password, :agreement, :locale)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def account_params
 | 
			
		||||
    @params.slice(:username)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def invite_request_params
 | 
			
		||||
    { text: @params[:reason] }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def allowed_registrations?
 | 
			
		||||
    Setting.registrations_mode != 'none' && !Rails.configuration.x.single_user_mode
 | 
			
		||||
    registrations_open? && !single_user_mode? && !omniauth_only? && !ip_blocked?
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def registrations_open?
 | 
			
		||||
    Setting.registrations_mode != 'none'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def single_user_mode?
 | 
			
		||||
    Rails.configuration.x.single_user_mode
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def omniauth_only?
 | 
			
		||||
    ENV['OMNIAUTH_ONLY'] == 'true'
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def ip_blocked?
 | 
			
		||||
    IpBlock.where(severity: :sign_up_block).where('ip >>= ?', @remote_ip.to_s).exists?
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,6 +85,7 @@ en:
 | 
			
		|||
        ip: Enter an IPv4 or IPv6 address. You can block entire ranges using the CIDR syntax. Be careful not to lock yourself out!
 | 
			
		||||
        severities:
 | 
			
		||||
          no_access: Block access to all resources
 | 
			
		||||
          sign_up_block: New sign-ups will not be possible
 | 
			
		||||
          sign_up_requires_approval: New sign-ups will require your approval
 | 
			
		||||
        severity: Choose what will happen with requests from this IP
 | 
			
		||||
      rule:
 | 
			
		||||
| 
						 | 
				
			
			@ -219,6 +220,7 @@ en:
 | 
			
		|||
        ip: IP
 | 
			
		||||
        severities:
 | 
			
		||||
          no_access: Block access
 | 
			
		||||
          sign_up_block: Block sign-ups
 | 
			
		||||
          sign_up_requires_approval: Limit sign-ups
 | 
			
		||||
        severity: Rule
 | 
			
		||||
      notification_emails:
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ RSpec.describe AppSignUpService, type: :service do
 | 
			
		|||
    it 'returns nil when registrations are closed' do
 | 
			
		||||
      tmp = Setting.registrations_mode
 | 
			
		||||
      Setting.registrations_mode = 'none'
 | 
			
		||||
      expect(subject.call(app, remote_ip, good_params)).to be_nil
 | 
			
		||||
      expect { subject.call(app, remote_ip, good_params) }.to raise_error Mastodon::NotPermittedError
 | 
			
		||||
      Setting.registrations_mode = tmp
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue