neocities/app/password_reset.rb
Kyle Drake d467e9be96 Force case insensitivity for new emails, existing.
There is a legacy bug I just caught, where many accounts would have the
same email but then have different casing. In extreme scenarios, this
would lead to them creating a new user with the same email, or having
issues with password reset and username lookup.

This doesn't merge in the existing duplicates, but makes sure to only
allow insensitive lowercase emails from here on out. It also will check
for emails in a case insensitive way for such things as resets and
logins if the sensitive lookup doesn't work.

The implementation was not wrong per se - email is supposed to be case sensitive
for usernames. But of course, nobody (nor do most/all email servers) treat
them that way, leading to confusion situations where the user sometimes
camelcases their email and then switches to lowercase later.
2017-12-08 22:13:27 -08:00

68 lines
1.8 KiB
Ruby

get '/password_reset' do
redirect '/' if signed_in?
erb :'password_reset'
end
post '/send_password_reset' do
if params[:email].blank?
flash[:error] = 'You must enter a valid email address.'
redirect '/password_reset'
end
sites = Site.get_recovery_sites_with_email params[:email]
if sites.length > 0
token = SecureRandom.uuid.gsub('-', '')
sites.each do |site|
next unless site.parent?
site.password_reset_token = token
site.save_changes validate: false
body = <<-EOT
Hello! This is the Neocities cat, and I have received a password reset request for your e-mail address.
Go to this URL to reset your password: https://neocities.org/password_reset_confirm?username=#{Rack::Utils.escape(site.username)}&token=#{token}
If you didn't request this password reset, you can ignore it. Or hide under a bed. Or take a nap. Your call.
Meow,
the Neocities Cat
EOT
body.strip!
EmailWorker.perform_async({
from: 'web@neocities.org',
to: params[:email],
subject: '[Neocities] Password Reset',
body: body
})
end
end
flash[:success] = 'If your email was valid (and used by a site), the Neocities Cat will send an e-mail to your account with password reset instructions.'
redirect '/'
end
get '/password_reset_confirm' do
if params[:token].nil? || params[:token].strip.empty?
flash[:error] = 'Token cannot be empty.'
redirect '/'
end
reset_site = Site.where(username: params[:username], password_reset_token: params[:token]).first
if reset_site.nil?
flash[:error] = 'Could not find a site with this username and token.'
redirect '/'
end
reset_site.password_reset_token = nil
reset_site.password_reset_confirmed = true
reset_site.save_changes
session[:id] = reset_site.id
redirect '/settings#password'
end