Skip to content

Commit 13d1469

Browse files
committed
verification should work even without login
It should depend on the user id in the token, not in the signed in user id. Additionally it shouldn't even require a signed in user, but if there's one, it should be the same as in the token.
1 parent df82470 commit 13d1469

File tree

2 files changed

+63
-4
lines changed

2 files changed

+63
-4
lines changed

app/controllers/verifications_controller.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,23 @@ def handle_register(token)
6767
end
6868

6969
def handle_add_alias(token)
70-
require_authentication
70+
user = token.user
71+
return redirect_to root_path, alert: 'Invalid token user' unless user
72+
73+
if user_signed_in? && current_user.id != user.id
74+
return redirect_to settings_path, alert: 'This verification link belongs to a different user.'
75+
end
76+
7177
email = token.email
72-
if Alias.by_email(email).where.not(user_id: [nil, current_user.id]).exists?
78+
if Alias.by_email(email).where.not(user_id: [nil, user.id]).exists?
7379
return redirect_to settings_path, alert: 'Email is linked to another account. Delete that account first to release it.'
7480
end
7581

7682
aliases = Alias.by_email(email)
7783
if aliases.exists?
78-
aliases.update_all(user_id: current_user.id, verified_at: Time.current)
84+
aliases.update_all(user_id: user.id, verified_at: Time.current)
7985
else
80-
Alias.create!(user: current_user, name: email, email: email, verified_at: Time.current)
86+
Alias.create!(user: user, name: email, email: email, verified_at: Time.current)
8187
end
8288

8389
redirect_to settings_path, notice: 'Email added and verified.'

spec/requests/emails_management_spec.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ def sign_in(email:, password: 'secret')
2323
end
2424

2525
raw = extract_raw_token_from_mailer
26+
27+
# Simulate user clicking verification link while logged out (no session).
28+
delete session_path
29+
2630
get verification_path(token: raw)
2731
expect(response).to redirect_to(settings_path)
2832

@@ -45,6 +49,55 @@ def sign_in(email:, password: 'secret')
4549
expect(response).to redirect_to(settings_path)
4650
end
4751

52+
it 'attaches all matching aliases when the email exists multiple times' do
53+
user = create(:user, password: 'secret', password_confirmation: 'secret')
54+
create(:alias, user: user, email: 'me-multi@example.com', primary_alias: true)
55+
Alias.by_email('me-multi@example.com').update_all(verified_at: Time.current)
56+
57+
# Legacy duplicates for the same email (different names)
58+
create(:alias, email: 'multi@example.com', name: 'Old One')
59+
create(:alias, email: 'multi@example.com', name: 'Older One')
60+
61+
sign_in(email: 'me-multi@example.com')
62+
63+
perform_enqueued_jobs do
64+
post emails_path, params: { email: 'multi@example.com' }
65+
expect(response).to redirect_to(settings_path)
66+
end
67+
68+
raw = extract_raw_token_from_mailer
69+
get verification_path(token: raw)
70+
expect(response).to redirect_to(settings_path)
71+
72+
aliases = Alias.by_email('multi@example.com')
73+
expect(aliases.count).to eq(2)
74+
expect(aliases.pluck(:user_id).uniq).to eq([user.id])
75+
expect(aliases.where(verified_at: nil)).to be_empty
76+
end
77+
78+
it 'rejects verification when logged in as a different user than the token user' do
79+
token_user = create(:user, password: 'secret', password_confirmation: 'secret')
80+
create(:alias, user: token_user, email: 'token-user@example.com', primary_alias: true)
81+
Alias.by_email('token-user@example.com').update_all(verified_at: Time.current)
82+
83+
other_user = create(:user, password: 'secret', password_confirmation: 'secret')
84+
create(:alias, user: other_user, email: 'other@example.com', primary_alias: true)
85+
Alias.by_email('other@example.com').update_all(verified_at: Time.current)
86+
87+
# Simulate an existing verification token for token_user.
88+
token, raw = UserToken.issue!(purpose: 'add_alias', user: token_user, email: 'token-user@example.com', ttl: 1.hour)
89+
90+
sign_in(email: 'other@example.com')
91+
92+
get verification_path(token: raw)
93+
94+
expect(response).to redirect_to(settings_path)
95+
expect(flash[:alert]).to match(/different user/)
96+
expect(Alias.by_email('token-user@example.com').pluck(:user_id).uniq).to eq([token_user.id])
97+
ensure
98+
token&.destroy
99+
end
100+
48101
def extract_raw_token_from_mailer
49102
mail = ActionMailer::Base.deliveries.last
50103
expect(mail).to be_present

0 commit comments

Comments
 (0)