Skip to content

Commit 3277633

Browse files
committed
Validate Identity email address
using the "standard" email regexp provided in the Ruby URI library. The form field will validate this in the browser, but if bots are creating identities, they can put whatever they want in here. So let's add some protection against that. ref: https://app.fizzy.do/5986089/cards/3276
1 parent 03e4f86 commit 3277633

File tree

3 files changed

+30
-0
lines changed

3 files changed

+30
-0
lines changed

app/models/identity.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class Identity < ApplicationRecord
1010

1111
before_destroy :deactivate_users
1212

13+
validates :email_address, format: { with: URI::MailTo::EMAIL_REGEXP }
1314
normalizes :email_address, with: ->(value) { value.strip.downcase.presence }
1415

1516
def send_magic_link(**attributes)

test/controllers/signups_controller_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,18 @@ class SignupsControllerTest < ActionDispatch::IntegrationTest
3434
end
3535
end
3636

37+
test "create with email address containing blanks" do
38+
untenanted do
39+
assert_no_difference -> { Identity.count } do
40+
assert_no_difference -> { MagicLink.count } do
41+
post signup_path, params: { signup: { email_address: "sam smith@example.com" } }
42+
end
43+
end
44+
45+
assert_response :unprocessable_entity
46+
end
47+
end
48+
3749
test "create for an authenticated user" do
3850
identity = identities(:kevin)
3951
sign_in_as identity

test/models/identity_test.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,23 @@ class IdentityTest < ActiveSupport::TestCase
1313
end
1414
end
1515

16+
test "email address format validation" do
17+
invalid_emails = [
18+
"sam smith@example.com", # space in local part
19+
"@example.com", # missing local part
20+
"test@", # missing domain
21+
"test", # missing @ and domain
22+
"<script>@example.com", # angle brackets
23+
"test@example.com\nX-Inject:" # newline (header injection attempt)
24+
]
25+
26+
invalid_emails.each do |email|
27+
identity = Identity.new(email_address: email)
28+
assert_not identity.valid?, "expected #{email.inspect} to be invalid"
29+
assert identity.errors[:email_address].any?, "expected error on email_address for #{email.inspect}"
30+
end
31+
end
32+
1633
test "join" do
1734
identity = identities(:david)
1835
account = accounts(:initech)

0 commit comments

Comments
 (0)