Invite link can't be used to log in after you set a password or sign in with 3rd party

This commit is contained in:
Neil Lalonde 2014-01-21 16:53:46 -05:00
parent 1dbc1c56b4
commit da825451d0
6 changed files with 60 additions and 5 deletions

View file

@ -27,6 +27,9 @@ class SessionController < ApplicationController
return
end
# User signed on with username and password, so let's prevent the invite link
# from being used to log in (if one exists).
Invite.invalidate_for_email(user.email)
else
invalid_credentials
return

View file

@ -85,8 +85,8 @@ class Users::OmniauthCallbacksController < ApplicationController
# log on any account that is active with forum access
if Guardian.new(user).can_access_forum? && user.active
log_on_user(user)
# don't carry around old auth info, perhaps move elsewhere
session[:authentication] = nil
Invite.invalidate_for_email(user.email) # invite link can't be used to log in anymore
session[:authentication] = nil # don't carry around old auth info, perhaps move elsewhere
@data.authenticated = true
else
if SiteSetting.must_approve_users? && !user.approved?

View file

@ -173,7 +173,10 @@ class UsersController < ApplicationController
raise Discourse::InvalidParameters.new(:password) unless params[:password].present?
@user.password = params[:password]
@user.password_required!
logon_after_password_reset if @user.save
if @user.save
Invite.invalidate_for_email(@user.email) # invite link can't be used to log in anymore
logon_after_password_reset
end
end
render layout: 'no_js'
end

View file

@ -26,7 +26,8 @@ class Invite < ActiveRecord::Base
def user_doesnt_already_exist
@email_already_exists = false
return if email.blank?
if User.where("email = ?", Email.downcase(email)).exists?
u = User.where("email = ?", Email.downcase(email)).first
if u && u.id != self.user_id
@email_already_exists = true
errors.add(:email)
end
@ -40,8 +41,13 @@ class Invite < ActiveRecord::Base
created_at < SiteSetting.invite_expiry_days.days.ago
end
# link_valid? indicates whether the invite link can be used to log in to the site
def link_valid?
invalidated_at.nil?
end
def redeem
InviteRedeemer.new(self).redeem unless expired? || destroyed?
InviteRedeemer.new(self).redeem unless expired? || destroyed? || !link_valid?
end
@ -100,6 +106,15 @@ class Invite < ActiveRecord::Base
rails4? ? all : scoped
end
end
def self.invalidate_for_email(email)
i = Invite.where(email: Email.downcase(email)).first
if i
i.invalidated_at = Time.zone.now
i.save
end
i
end
end
# == Schema Information

View file

@ -0,0 +1,5 @@
class AddInvalidatedAtToInvites < ActiveRecord::Migration
def change
add_column :invites, :invalidated_at, :datetime
end
end

View file

@ -167,6 +167,11 @@ describe Invite do
invite.redeem.should be_blank
end
it "won't redeem an invalidated invite" do
invite.invalidated_at = 1.day.ago
invite.redeem.should be_blank
end
context 'invite trust levels' do
it "returns the trust level in default_invitee_trust_level" do
@ -350,4 +355,28 @@ describe Invite do
expect(invites.first).to eq redeemed_invite
end
end
describe '.invalidate_for_email' do
let(:email) { 'invite.me@example.com' }
subject { described_class.invalidate_for_email(email) }
it 'returns nil if there is no invite for the given email' do
subject.should == nil
end
it 'sets the matching invite to be invalid' do
invite = Fabricate(:invite, invited_by: Fabricate(:user), user_id: nil, email: email)
subject.should == invite
subject.link_valid?.should == false
subject.should be_valid
end
it 'sets the matching invite to be invalid without being case-sensitive' do
invite = Fabricate(:invite, invited_by: Fabricate(:user), user_id: nil, email: 'invite.me2@Example.COM')
result = described_class.invalidate_for_email('invite.me2@EXAMPLE.com')
result.should == invite
result.link_valid?.should == false
result.should be_valid
end
end
end