about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--app/controllers/auth/registrations_controller.rb6
-rw-r--r--app/models/ip_block.rb1
-rw-r--r--app/services/app_sign_up_service.rb66
-rw-r--r--config/locales/simple_form.en.yml2
-rw-r--r--spec/services/app_sign_up_service_spec.rb2
5 files changed, 64 insertions, 13 deletions
diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb
index 1c3adbd78..7e86e01ba 100644
--- a/app/controllers/auth/registrations_controller.rb
+++ b/app/controllers/auth/registrations_controller.rb
@@ -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]
diff --git a/app/models/ip_block.rb b/app/models/ip_block.rb
index aedd3ca0d..e1ab59806 100644
--- a/app/models/ip_block.rb
+++ b/app/models/ip_block.rb
@@ -19,6 +19,7 @@ class IpBlock < ApplicationRecord
 
   enum severity: {
     sign_up_requires_approval: 5000,
+    sign_up_block: 5500,
     no_access: 9999,
   }
 
diff --git a/app/services/app_sign_up_service.rb b/app/services/app_sign_up_service.rb
index e00694157..3833327bb 100644
--- a/app/services/app_sign_up_service.rb
+++ b/app/services/app_sign_up_service.rb
@@ -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
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index c17a62cbe..28f78d500 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -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:
diff --git a/spec/services/app_sign_up_service_spec.rb b/spec/services/app_sign_up_service_spec.rb
index e0c83b704..8ec4d4a7a 100644
--- a/spec/services/app_sign_up_service_spec.rb
+++ b/spec/services/app_sign_up_service_spec.rb
@@ -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