mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 00:58:57 +08:00
SECURITY: prevent reuse of password reset
This commit is contained in:
parent
9db22bfd3d
commit
c10dfe0d1b
@ -9,6 +9,7 @@ require_dependency 'json_error'
|
||||
require_dependency 'letter_avatar'
|
||||
require_dependency 'distributed_cache'
|
||||
require_dependency 'global_path'
|
||||
require_dependency 'secure_session'
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include CurrentUser
|
||||
@ -332,6 +333,10 @@ class ApplicationController < ActionController::Base
|
||||
request.session_options[:skip] = true
|
||||
end
|
||||
|
||||
def secure_session
|
||||
SecureSession.new(session["secure_session_id"] ||= SecureRandom.hex)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def locale_from_header
|
||||
@ -501,6 +506,7 @@ class ApplicationController < ActionController::Base
|
||||
render_to_string status: status, layout: layout, formats: [:html], template: '/exceptions/not_found'
|
||||
end
|
||||
|
||||
|
||||
protected
|
||||
|
||||
def render_post_json(post, add_raw=true)
|
||||
|
@ -362,19 +362,21 @@ class UsersController < ApplicationController
|
||||
def password_reset
|
||||
expires_now
|
||||
|
||||
if EmailToken.valid_token_format?(params[:token])
|
||||
token = params[:token]
|
||||
|
||||
if EmailToken.valid_token_format?(token)
|
||||
if request.put?
|
||||
@user = EmailToken.confirm(params[:token])
|
||||
@user = EmailToken.confirm(token)
|
||||
else
|
||||
email_token = EmailToken.confirmable(params[:token])
|
||||
email_token = EmailToken.confirmable(token)
|
||||
@user = email_token.try(:user)
|
||||
end
|
||||
|
||||
if @user
|
||||
session["password-#{params[:token]}"] = @user.id
|
||||
secure_session["password-#{token}"] = @user.id
|
||||
else
|
||||
user_id = session["password-#{params[:token]}"]
|
||||
@user = User.find(user_id) if user_id
|
||||
user_id = secure_session["password-#{token}"].to_i
|
||||
@user = User.find(user_id) if user_id > 0
|
||||
end
|
||||
else
|
||||
@invalid_token = true
|
||||
@ -393,6 +395,7 @@ class UsersController < ApplicationController
|
||||
@user.auth_token = nil
|
||||
if @user.save
|
||||
Invite.invalidate_for_email(@user.email) # invite link can't be used to log in anymore
|
||||
secure_session["password-#{token}"] = nil
|
||||
logon_after_password_reset
|
||||
end
|
||||
end
|
||||
|
18
lib/secure_session.rb
Normal file
18
lib/secure_session.rb
Normal file
@ -0,0 +1,18 @@
|
||||
# session that is not stored in cookie, expires after 1.hour unconditionally
|
||||
class SecureSession
|
||||
def initialize(prefix)
|
||||
@prefix = prefix
|
||||
end
|
||||
|
||||
def [](key)
|
||||
$redis.get("#{@prefix}#{key}")
|
||||
end
|
||||
|
||||
def []=(key,val)
|
||||
if val == nil
|
||||
$redis.del("#{@prefix}#{key}")
|
||||
else
|
||||
$redis.setex("#{@prefix}#{key}", 1.hour, val.to_s)
|
||||
end
|
||||
end
|
||||
end
|
16
spec/components/secure_session_spec.rb
Normal file
16
spec/components/secure_session_spec.rb
Normal file
@ -0,0 +1,16 @@
|
||||
require 'rails_helper'
|
||||
require_dependency 'secure_session'
|
||||
|
||||
describe SecureSession do
|
||||
it "operates correctly" do
|
||||
s = SecureSession.new("abc")
|
||||
|
||||
s["hello"] = "world"
|
||||
s["foo"] = "bar"
|
||||
expect(s["hello"]).to eq("world")
|
||||
expect(s["foo"]).to eq("bar")
|
||||
|
||||
s["hello"] = nil
|
||||
expect(s["hello"]).to eq(nil)
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user