Make password resets closer to old e6 password resets

This commit is contained in:
Kira 2019-06-12 21:39:45 -07:00
parent 9b21dfe81d
commit 583cd7e20d
9 changed files with 51 additions and 66 deletions

View File

@ -6,33 +6,34 @@ module Maintenance
end
def create
@nonce = UserPasswordResetNonce.create(nonce_params)
if @nonce.errors.any?
redirect_to new_maintenance_user_password_reset_path, :notice => @nonce.errors.full_messages.join("; ")
else
redirect_to new_maintenance_user_password_reset_path, :notice => "Email request sent"
::User.where('email = ?', params[:email]).each do |user|
next if user.is_mod?
UserPasswordResetNonce.create(user_id: user.id)
end
redirect_to new_maintenance_user_password_reset_path, :notice => "If your email was on file, an email has been sent your way. It should arrive within the next few minutes. Make sure to check your spam folder."
end
def edit
@nonce = UserPasswordResetNonce.where(:email => params[:email], :key => params[:key]).first
@nonce = UserPasswordResetNonce.where('user_id = ? AND key = ?', params[:uid], params[:key]).first
end
def update
@nonce = UserPasswordResetNonce.where(:email => params[:email], :key => params[:key]).first
@nonce = UserPasswordResetNonce.where('user_id = ? AND key = ?', params[:uid], params[:key]).first
if @nonce
@nonce.reset_user!
@nonce.destroy
redirect_to new_maintenance_user_password_reset_path, :notice => "Password reset; email delivered with new password"
if @nonce.expired?
return redirect_to new_maintenance_user_password_reset_path, notice: "Reset expired"
end
if @nonce.reset_user!(params[:password], params[:password_confirm])
@nonce.destroy
redirect_to new_maintenance_user_password_reset_path, :notice => "Password reset"
else
redirect_to new_maintenance_user_password_reset_path, notice: "Passwords do not match"
end
else
redirect_to new_maintenance_user_password_reset_path, :notice => "Invalid key"
redirect_to new_maintenance_user_password_reset_path, :notice => "Invalid reset token"
end
end
def nonce_params
params.fetch(:nonce, {}).permit([:email])
end
end
end
end

View File

@ -4,13 +4,7 @@ module Maintenance
def reset_request(user, nonce)
@user = user
@nonce = nonce
mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} password reset request", :from => Danbooru.config.contact_email)
end
def confirmation(user, new_password)
@user = user
@new_password = new_password
mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} password reset confirmation", :from => Danbooru.config.contact_email)
mail(:to => @user.email, :subject => "#{Danbooru.config.app_name} password reset", :from => Danbooru.config.contact_email)
end
end
end

View File

@ -192,26 +192,6 @@ class User < ApplicationRecord
def upgrade_password(pass)
self.update_columns(password_hash: '', bcrypt_password_hash: User.bcrypt(pass))
end
def reset_password
consonants = "bcdfghjklmnpqrstvqxyz"
vowels = "aeiou"
pass = ""
6.times do
pass << consonants[rand(21), 1]
pass << vowels[rand(5), 1]
end
pass << rand(100).to_s
update_column(:bcrypt_password_hash, User.bcrypt(pass))
pass
end
def reset_password_and_deliver_notice
new_password = reset_password()
Maintenance::User::PasswordResetMailer.confirmation(self, new_password).deliver_now
end
end
module AuthenticationMethods
@ -220,7 +200,7 @@ class User < ApplicationRecord
module ClassMethods
def authenticate(name, pass)
user = find_by_name(name)
if user && user.password_hash && PBKDF2.validate_password(pass, user.password_hash)
if user && user.password_hash.present? && PBKDF2.validate_password(pass, user.password_hash)
user.upgrade_password(pass)
user
elsif user && user.bcrypt_password_hash && user.bcrypt_password == pass

View File

@ -1,29 +1,25 @@
class UserPasswordResetNonce < ApplicationRecord
has_secure_token :key
validates_presence_of :email
validate :validate_existence_of_email
after_create :deliver_notice
belongs_to :user
def self.prune!
where("created_at < ?", 1.week.ago).destroy_all
where("created_at < ?", 2.days.ago).destroy_all
end
def deliver_notice
Maintenance::User::PasswordResetMailer.reset_request(user, self).deliver_now
end
def validate_existence_of_email
if !User.with_email(email).exists?
errors[:email] << "is invalid"
return false
if user.email.present?
Maintenance::User::PasswordResetMailer.reset_request(user, self).deliver_now
end
end
def reset_user!
user.reset_password_and_deliver_notice
def reset_user!(pass, confirm)
return false if !ActiveSupport::SecurityUtils.secure_compare(pass, confirm)
user.upgrade_password(pass)
true
end
def user
@user ||= User.with_email(email).first
def expired?
created_at < 24.hours.ago
end
end

View File

@ -1,4 +1,4 @@
<h1>Password Reset Request</h1>
<p>Someone has requested that the password for "<%= @user.name %>" for the website <%= Danbooru.config.app_name %> be reset. If you did not request this, then you can ignore this email.</p>
<p>To reset your password, please visit <%= link_to "this link", edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @nonce.key, :email => @nonce.email) %>.</p>
<p>To reset your password, please visit <%= link_to "this link", edit_maintenance_user_password_reset_url(:host => Danbooru.config.hostname, :only_path => false, :key => @nonce.key, :uid => @nonce.user_id) %>.</p>

View File

@ -4,13 +4,20 @@
<% if @nonce %>
<%= form_tag(maintenance_user_password_reset_path, :method => :put) do %>
<%= hidden_field_tag :email, params[:email] %>
<%= hidden_field_tag :uid, params[:uid] %>
<%= hidden_field_tag :key, params[:key] %>
<p>Do you wish to reset your password? A new password will be emailed to you.</p>
<div class="input">
<label for="password">Password</label>
<%= password_field_tag :password %>
</div>
<div class="input">
<label for="password_confirm">Confirm Password</label>
<%= password_field_tag :password_confirm %>
</div>
<%= submit_tag "Reset" %>
<% end %>
<% else %>
<p>Invalid key</p>
<p>Invalid reset</p>
<% end %>
</div>
</div>

View File

@ -4,12 +4,12 @@
<p>If you supplied an email address when signing up, <%= Danbooru.config.app_name %> can reset your password. You will receive an email confirming your request for a new password.</p>
<p>If you didn't supply a valid email address, you are out of luck.</p>
<p>If you didn't supply a valid email address, there is no way to recover your account.</p>
<%= form_tag(maintenance_user_password_reset_path, :class => "simple_form") do %>
<div class="input email required">
<label for="nonce_email" class="required">Email</label>
<%= text_field :nonce, :email %>
<%= text_field_tag :email %>
</div>
<%= submit_tag "Submit" %>
<% end %>

View File

@ -0,0 +1,6 @@
class FixPasswordResets < ActiveRecord::Migration[5.2]
def change
remove_column :user_password_reset_nonces, :email
add_column :user_password_reset_nonces, :user_id, :integer, null: false
end
end

View File

@ -2489,9 +2489,9 @@ ALTER SEQUENCE public.user_name_change_requests_id_seq OWNED BY public.user_name
CREATE TABLE public.user_password_reset_nonces (
id integer NOT NULL,
key character varying NOT NULL,
email character varying NOT NULL,
created_at timestamp without time zone,
updated_at timestamp without time zone
updated_at timestamp without time zone,
user_id integer NOT NULL
);
@ -5120,6 +5120,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20190510184237'),
('20190510184245'),
('20190602115848'),
('20190604125828');
('20190604125828'),
('20190613025850');