mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 10:20:58 -06:00
7c4e2d33fa
This security fix affects sites which have `SiteSetting.must_approve_users` enabled. There are intentional and unintentional cases where invited users can be auto approved and are deemed to have skipped the staff approval process. Instead of trying to reason about when auto-approval should happen, we have decided that enabling the `must_approve_users` setting going forward will just mean that all new users must be explicitly approved by a staff user in the review queue. The only case where users are auto approved is when the `auto_approve_email_domains` site setting is used. Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
253 lines
10 KiB
Ruby
253 lines
10 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
describe InviteRedeemer do
|
|
|
|
describe '.create_user_from_invite' do
|
|
it "should be created correctly" do
|
|
invite = Fabricate(:invite, email: 'walter.white@email.com')
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White')
|
|
expect(user.username).to eq('walter')
|
|
expect(user.name).to eq('Walter White')
|
|
expect(user.email).to eq('walter.white@email.com')
|
|
expect(user.approved).to eq(false)
|
|
expect(user.active).to eq(false)
|
|
end
|
|
|
|
it "can set the password and ip_address" do
|
|
password = 's3cure5tpasSw0rD'
|
|
ip_address = '192.168.1.1'
|
|
invite = Fabricate(:invite, email: 'walter.white@email.com')
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White', password: password, ip_address: ip_address)
|
|
expect(user).to have_password
|
|
expect(user.confirm_password?(password)).to eq(true)
|
|
expect(user.approved).to eq(false)
|
|
expect(user.ip_address).to eq(ip_address)
|
|
expect(user.registration_ip_address).to eq(ip_address)
|
|
end
|
|
|
|
it "raises exception with record and errors" do
|
|
error = nil
|
|
invite = Fabricate(:invite, email: 'walter.white@email.com')
|
|
begin
|
|
InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White', password: 'aaa')
|
|
rescue ActiveRecord::RecordInvalid => e
|
|
error = e
|
|
end
|
|
expect(error).to be_present
|
|
expect(error.record.errors[:password]).to be_present
|
|
end
|
|
|
|
it "should unstage user" do
|
|
staged_user = Fabricate(:staged, email: 'staged@account.com', active: true, username: 'staged1', name: 'Stage Name')
|
|
invite = Fabricate(:invite, email: 'staged@account.com')
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White')
|
|
|
|
expect(user.id).to eq(staged_user.id)
|
|
expect(user.username).to eq('walter')
|
|
expect(user.name).to eq('Walter White')
|
|
expect(user.staged).to eq(false)
|
|
expect(user.email).to eq('staged@account.com')
|
|
expect(user.approved).to eq(false)
|
|
end
|
|
|
|
it "activates user invited via email with a token" do
|
|
invite = Fabricate(:invite, invited_by: Fabricate(:admin), email: 'walter.white@email.com', emailed_status: Invite.emailed_status_types[:sent])
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White', email_token: invite.email_token)
|
|
|
|
expect(user.username).to eq('walter')
|
|
expect(user.name).to eq('Walter White')
|
|
expect(user.email).to eq('walter.white@email.com')
|
|
expect(user.approved).to eq(false)
|
|
expect(user.active).to eq(true)
|
|
end
|
|
|
|
it "does not activate user invited via email with a wrong token" do
|
|
invite = Fabricate(:invite, invited_by: Fabricate(:user), email: 'walter.white@email.com', emailed_status: Invite.emailed_status_types[:sent])
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White', email_token: 'wrong_token')
|
|
expect(user.active).to eq(false)
|
|
end
|
|
|
|
it "does not activate user invited via email without a token" do
|
|
invite = Fabricate(:invite, invited_by: Fabricate(:user), email: 'walter.white@email.com', emailed_status: Invite.emailed_status_types[:sent])
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White')
|
|
expect(user.active).to eq(false)
|
|
end
|
|
|
|
it "does not activate user invited via links" do
|
|
invite = Fabricate(:invite, email: 'walter.white@email.com', emailed_status: Invite.emailed_status_types[:not_required])
|
|
user = InviteRedeemer.create_user_from_invite(invite: invite, email: invite.email, username: 'walter', name: 'Walter White')
|
|
|
|
expect(user.username).to eq('walter')
|
|
expect(user.name).to eq('Walter White')
|
|
expect(user.email).to eq('walter.white@email.com')
|
|
expect(user.approved).to eq(false)
|
|
expect(user.active).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe "#redeem" do
|
|
fab!(:invite) { Fabricate(:invite, email: "foobar@example.com") }
|
|
let(:name) { 'john snow' }
|
|
let(:username) { 'kingofthenorth' }
|
|
let(:password) { 'know5nOthiNG' }
|
|
let(:invite_redeemer) { InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name) }
|
|
|
|
context "when must_approve_users setting is enabled" do
|
|
before do
|
|
SiteSetting.must_approve_users = true
|
|
end
|
|
|
|
it "should redeem an invite but not approve the user when invite is created by a staff user" do
|
|
inviter = invite.invited_by
|
|
inviter.update!(admin: true)
|
|
user = invite_redeemer.redeem
|
|
|
|
expect(user.name).to eq(name)
|
|
expect(user.username).to eq(username)
|
|
expect(user.invited_by).to eq(inviter)
|
|
expect(user.approved).to eq(false)
|
|
|
|
expect(inviter.notifications.count).to eq(1)
|
|
end
|
|
|
|
it "should redeem the invite but not approve the user when invite is created by a regular user" do
|
|
inviter = invite.invited_by
|
|
user = invite_redeemer.redeem
|
|
|
|
expect(user.name).to eq(name)
|
|
expect(user.username).to eq(username)
|
|
expect(user.invited_by).to eq(inviter)
|
|
expect(user.approved).to eq(false)
|
|
|
|
expect(inviter.notifications.count).to eq(1)
|
|
end
|
|
|
|
it "should redeem the invite and approve the user when user email is in auto_approve_email_domains setting" do
|
|
SiteSetting.auto_approve_email_domains = "example.com"
|
|
user = invite_redeemer.redeem
|
|
|
|
expect(user.name).to eq(name)
|
|
expect(user.username).to eq(username)
|
|
expect(user.approved).to eq(true)
|
|
expect(user.approved_by).to eq(Discourse.system_user)
|
|
end
|
|
end
|
|
|
|
it "should redeem the invite if invited by non staff and approve if staff not required to approve" do
|
|
inviter = invite.invited_by
|
|
user = invite_redeemer.redeem
|
|
|
|
expect(user.name).to eq(name)
|
|
expect(user.username).to eq(username)
|
|
expect(user.invited_by).to eq(inviter)
|
|
expect(inviter.notifications.count).to eq(1)
|
|
expect(user.approved).to eq(false)
|
|
end
|
|
|
|
it "should delete invite if invited_by user has been removed" do
|
|
invite.invited_by.destroy!
|
|
expect { invite.reload }.to raise_error(ActiveRecord::RecordNotFound)
|
|
end
|
|
|
|
it "can set password" do
|
|
user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password).redeem
|
|
expect(user).to have_password
|
|
expect(user.confirm_password?(password)).to eq(true)
|
|
expect(user.approved).to eq(false)
|
|
end
|
|
|
|
it "can set custom fields" do
|
|
required_field = Fabricate(:user_field)
|
|
optional_field = Fabricate(:user_field, required: false)
|
|
user_fields = {
|
|
required_field.id.to_s => 'value1',
|
|
optional_field.id.to_s => 'value2'
|
|
}
|
|
user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password, user_custom_fields: user_fields).redeem
|
|
|
|
expect(user).to be_present
|
|
expect(user.custom_fields["user_field_#{required_field.id}"]).to eq('value1')
|
|
expect(user.custom_fields["user_field_#{optional_field.id}"]).to eq('value2')
|
|
end
|
|
|
|
it "does not add user to group if inviter does not have permissions" do
|
|
group = Fabricate(:group, grant_trust_level: 2)
|
|
InvitedGroup.create(group_id: group.id, invite_id: invite.id)
|
|
user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password).redeem
|
|
|
|
expect(user.group_users.count).to eq(0)
|
|
end
|
|
|
|
it "adds user to group" do
|
|
group = Fabricate(:group, grant_trust_level: 2)
|
|
InvitedGroup.create(group_id: group.id, invite_id: invite.id)
|
|
group.add_owner(invite.invited_by)
|
|
|
|
user = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name, password: password).redeem
|
|
|
|
expect(user.group_users.count).to eq(4)
|
|
expect(user.trust_level).to eq(2)
|
|
end
|
|
|
|
it "only allows one user to be created per invite" do
|
|
user = invite_redeemer.redeem
|
|
invite.reload
|
|
|
|
user.email = "john@example.com"
|
|
user.save!
|
|
|
|
another_invite_redeemer = InviteRedeemer.new(invite: invite, email: invite.email, username: username, name: name)
|
|
another_user = another_invite_redeemer.redeem
|
|
expect(another_user).to eq(nil)
|
|
end
|
|
|
|
it "should correctly update the invite redeemed_at date" do
|
|
SiteSetting.invite_expiry_days = 2
|
|
invite.update!(created_at: 10.days.ago)
|
|
|
|
inviter = invite.invited_by
|
|
inviter.admin = true
|
|
user = invite_redeemer.redeem
|
|
invite.reload
|
|
|
|
expect(user.invited_by).to eq(inviter)
|
|
expect(inviter.notifications.count).to eq(1)
|
|
expect(invite.invited_users.first).to be_present
|
|
end
|
|
|
|
context 'invite_link' do
|
|
fab!(:invite_link) { Fabricate(:invite, email: nil, max_redemptions_allowed: 5, expires_at: 1.month.from_now, emailed_status: Invite.emailed_status_types[:not_required]) }
|
|
let(:invite_redeemer) { InviteRedeemer.new(invite: invite_link, email: 'foo@example.com') }
|
|
|
|
it 'works as expected' do
|
|
user = invite_redeemer.redeem
|
|
invite_link.reload
|
|
|
|
expect(user.send_welcome_message).to eq(true)
|
|
expect(user.trust_level).to eq(SiteSetting.default_invitee_trust_level)
|
|
expect(user.active).to eq(false)
|
|
expect(invite_link.redemption_count).to eq(1)
|
|
end
|
|
|
|
it "should not redeem the invite if InvitedUser record already exists for email" do
|
|
user = invite_redeemer.redeem
|
|
invite_link.reload
|
|
|
|
another_invite_redeemer = InviteRedeemer.new(invite: invite_link, email: 'foo@example.com')
|
|
another_user = another_invite_redeemer.redeem
|
|
expect(another_user).to eq(nil)
|
|
end
|
|
|
|
it "should redeem the invite if InvitedUser record does not exists for email" do
|
|
user = invite_redeemer.redeem
|
|
invite_link.reload
|
|
|
|
another_invite_redeemer = InviteRedeemer.new(invite: invite_link, email: 'bar@example.com')
|
|
another_user = another_invite_redeemer.redeem
|
|
expect(another_user.is_a?(User)).to eq(true)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|