Skip to content

Commit 3de6ba8

Browse files
committed
Added feature: Limit Spam Sign Ups in Rails Apps
See https://railsdesigner.com/saas/limit-spam-rails-signups/ for details
1 parent eae77d6 commit 3de6ba8

File tree

7 files changed

+38
-0
lines changed

7 files changed

+38
-0
lines changed

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,5 @@ group :development do
5555
# Use console on exceptions pages [https://github.com/rails/web-console]
5656
gem "web-console"
5757
end
58+
59+
gem "invisible_captcha", "~> 2.3"

Gemfile.lock

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ GEM
108108
actionpack (>= 6.0.0)
109109
activesupport (>= 6.0.0)
110110
railties (>= 6.0.0)
111+
invisible_captcha (2.3.0)
112+
rails (>= 5.2)
111113
io-console (0.7.2)
112114
irb (1.14.1)
113115
rdoc (>= 4.0.0)
@@ -347,6 +349,7 @@ DEPENDENCIES
347349
brakeman
348350
debug
349351
importmap-rails
352+
invisible_captcha (~> 2.3)
350353
jbuilder
351354
kamal
352355
propshaft

app/controllers/signups_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
class SignupsController < ApplicationController
22
allow_unauthenticated_access only: %w[new create]
3+
invisible_captcha only: %w[create], timestamp_enabled: false
34

45
def new
56
@signup = Signup.new

app/models/signup.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class Signup
1010
validates :password, length: 8..128
1111
validates :terms, acceptance: true
1212

13+
validates :email_address, is_not_spam: true
14+
1315
def save
1416
if valid?
1517
User.create!(email_address: email_address, password: password).tap do |user|
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
class IsNotSpamValidator < ActiveModel::EachValidator
2+
def validate_each(record, attribute, email_address)
3+
return if email_address.blank?
4+
5+
if spam? email_address
6+
record.errors.add(attribute, options[:message] || "appears suspicious")
7+
end
8+
end
9+
10+
private
11+
12+
MAXIMUM_DOTS = 3
13+
14+
def spam?(email_address)
15+
local_part, domain = email_address.split("@", 2)
16+
17+
disposable?(domain) || excessive_dots_in?(local_part)
18+
end
19+
20+
def disposable?(domain) = disposable_email_providers.include?(domain)
21+
22+
# make sure to copy the list of disposable emails providers from:
23+
# https://github.com/disposable-email-domains/disposable-email-domains
24+
#
25+
def disposable_email_providers = File.read("config/disposable_email_providers.txt").split("\n")
26+
27+
def excessive_dots_in?(local_part) = local_part.count(".") >= MAXIMUM_DOTS
28+
end

app/views/signups/new.html.erb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@
88
<%= form.check_box :terms %>
99
<%= form.label :terms %><br>
1010

11+
<%= invisible_captcha %>
12+
1113
<%= form.submit "Sign up" %>
1214
<% end %>

config/disposable_email_providers.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)