2019-04-29 20:27:42 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2022-07-27 22:27:38 -04:00
|
|
|
RSpec.describe SpamRule::FlagSockpuppets do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:user1) { Fabricate(:user, ip_address: "182.189.119.174") }
|
|
|
|
fab!(:post1) { Fabricate(:post, user: user1, topic: Fabricate(:topic, user: user1)) }
|
2013-10-25 13:25:02 -04:00
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
describe "#perform" do
|
2013-10-25 13:25:02 -04:00
|
|
|
subject(:perform) { rule.perform }
|
|
|
|
|
2023-06-21 10:00:19 -04:00
|
|
|
let(:rule) { described_class.new(post1) }
|
|
|
|
|
2013-10-25 13:25:02 -04:00
|
|
|
it "does nothing if flag_sockpuppets is disabled" do
|
2017-07-07 02:09:14 -04:00
|
|
|
SiteSetting.flag_sockpuppets = false
|
2013-10-25 13:25:02 -04:00
|
|
|
rule.expects(:reply_is_from_sockpuppet?).never
|
|
|
|
rule.expects(:flag_sockpuppet_users).never
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(perform).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
context "when flag_sockpuppets is enabled" do
|
2017-07-07 02:09:14 -04:00
|
|
|
before { SiteSetting.flag_sockpuppets = true }
|
2013-10-25 13:25:02 -04:00
|
|
|
|
|
|
|
it "flags posts when it should" do
|
2023-12-06 07:19:09 -05:00
|
|
|
rule.expects(:reply_is_from_sockpuppet?).returns(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
rule.expects(:flag_sockpuppet_users).once
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(perform).to eq(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't flag posts when it shouldn't" do
|
|
|
|
rule.expects(:reply_is_from_sockpuppet?).returns(false)
|
|
|
|
rule.expects(:flag_sockpuppet_users).never
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(perform).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
describe "#reply_is_from_sockpuppet?" do
|
2013-10-25 13:25:02 -04:00
|
|
|
it "is false for the first post in a topic" do
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post1).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if users have different IP addresses" do
|
|
|
|
post2 =
|
|
|
|
Fabricate(:post, user: Fabricate(:user, ip_address: "182.189.199.199"), topic: post1.topic)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true if users have the same IP address and are new" do
|
|
|
|
post2 =
|
|
|
|
Fabricate(:post, user: Fabricate(:user, ip_address: user1.ip_address), topic: post1.topic)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
2020-07-26 20:23:54 -04:00
|
|
|
it "is false if the ip address is allowlisted" do
|
|
|
|
ScreenedIpAddress.stubs(:is_allowed?).with(user1.ip_address).returns(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
post2 =
|
|
|
|
Fabricate(:post, user: Fabricate(:user, ip_address: user1.ip_address), topic: post1.topic)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if reply and first post are from the same user" do
|
|
|
|
post2 = Fabricate(:post, user: user1, topic: post1.topic)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if first post user is staff" do
|
|
|
|
staff1 = Fabricate(:admin, ip_address: "182.189.119.174")
|
|
|
|
staff_post1 = Fabricate(:post, user: staff1, topic: Fabricate(:topic, user: staff1))
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:user, ip_address: staff1.ip_address),
|
|
|
|
topic: staff_post1.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if second post user is staff" do
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:moderator, ip_address: user1.ip_address),
|
|
|
|
topic: post1.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if both users are staff" do
|
|
|
|
staff1 = Fabricate(:moderator, ip_address: "182.189.119.174")
|
|
|
|
staff_post1 = Fabricate(:post, user: staff1, topic: Fabricate(:topic, user: staff1))
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:admin, ip_address: staff1.ip_address),
|
|
|
|
topic: staff_post1.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true if first post user was created over 24 hours ago and has trust level higher than 0" do
|
2014-09-05 01:20:39 -04:00
|
|
|
old_user =
|
|
|
|
Fabricate(
|
|
|
|
:user,
|
|
|
|
ip_address: "182.189.119.174",
|
|
|
|
created_at: 25.hours.ago,
|
|
|
|
trust_level: TrustLevel[1],
|
|
|
|
)
|
2013-10-25 13:25:02 -04:00
|
|
|
first_post = Fabricate(:post, user: old_user, topic: Fabricate(:topic, user: old_user))
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:user, ip_address: old_user.ip_address),
|
|
|
|
topic: first_post.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is false if second post user was created over 24 hours ago and has trust level higher than 0" do
|
2014-09-05 01:20:39 -04:00
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user:
|
|
|
|
Fabricate(
|
|
|
|
:user,
|
|
|
|
ip_address: user1.ip_address,
|
|
|
|
created_at: 25.hours.ago,
|
|
|
|
trust_level: TrustLevel[1],
|
|
|
|
),
|
|
|
|
topic: post1.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true if first post user was created less that 24 hours ago and has trust level higher than 0" do
|
2014-09-05 01:20:39 -04:00
|
|
|
new_user =
|
|
|
|
Fabricate(
|
|
|
|
:user,
|
|
|
|
ip_address: "182.189.119.174",
|
|
|
|
created_at: 1.hour.ago,
|
|
|
|
trust_level: TrustLevel[1],
|
|
|
|
)
|
2013-10-25 13:25:02 -04:00
|
|
|
first_post = Fabricate(:post, user: new_user, topic: Fabricate(:topic, user: new_user))
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:user, ip_address: new_user.ip_address),
|
|
|
|
topic: first_post.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "is true if second user was created less that 24 hours ago and has trust level higher than 0" do
|
2014-09-05 01:20:39 -04:00
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user:
|
|
|
|
Fabricate(
|
|
|
|
:user,
|
|
|
|
ip_address: user1.ip_address,
|
|
|
|
created_at: 23.hours.ago,
|
|
|
|
trust_level: TrustLevel[1],
|
|
|
|
),
|
|
|
|
topic: post1.topic,
|
|
|
|
)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(true)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# A weird case
|
|
|
|
it "is false when user is nil on first post" do
|
|
|
|
post1.user = nil
|
|
|
|
post1.save!
|
|
|
|
post2 = Fabricate(:post, user: Fabricate(:user), topic: post1.topic)
|
2015-04-25 11:18:35 -04:00
|
|
|
expect(described_class.new(post2).reply_is_from_sockpuppet?).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-27 12:14:14 -04:00
|
|
|
describe "#flag_sockpuppet_users" do
|
2019-05-06 23:12:20 -04:00
|
|
|
fab!(:post2) do
|
|
|
|
Fabricate(:post, user: Fabricate(:user, ip_address: user1.ip_address), topic: post1.topic)
|
2023-01-09 06:18:21 -05:00
|
|
|
end
|
2019-02-04 15:05:37 -05:00
|
|
|
let(:system) { Discourse.system_user }
|
|
|
|
let(:spam) { PostActionType.types[:spam] }
|
2013-10-25 13:25:02 -04:00
|
|
|
|
|
|
|
it "flags post and first post if both users are new" do
|
|
|
|
described_class.new(post2).flag_sockpuppet_users
|
2019-02-04 15:05:37 -05:00
|
|
|
|
|
|
|
expect(PostAction.where(user: system, post: post1, post_action_type_id: spam).exists?).to eq(
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
expect(PostAction.where(user: system, post: post2, post_action_type_id: spam).exists?).to eq(
|
|
|
|
true,
|
|
|
|
)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't flag the first post more than once" do
|
|
|
|
described_class.new(post2).flag_sockpuppet_users
|
2019-02-04 15:05:37 -05:00
|
|
|
|
|
|
|
expect(PostAction.where(user: system, post: post2, post_action_type_id: spam).exists?).to eq(
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
expect(PostAction.where(post: post2, post_action_type_id: spam).count).to eq(1)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't flag the first post if the user is not new" do
|
2014-09-05 01:20:39 -04:00
|
|
|
old_user =
|
|
|
|
Fabricate(
|
|
|
|
:user,
|
|
|
|
ip_address: "182.189.119.174",
|
|
|
|
created_at: 25.hours.ago,
|
|
|
|
trust_level: TrustLevel[1],
|
|
|
|
)
|
2013-10-25 13:25:02 -04:00
|
|
|
first_post = Fabricate(:post, user: old_user, topic: Fabricate(:topic, user: old_user))
|
|
|
|
post2 =
|
|
|
|
Fabricate(
|
|
|
|
:post,
|
|
|
|
user: Fabricate(:user, ip_address: old_user.ip_address),
|
|
|
|
topic: first_post.topic,
|
|
|
|
)
|
2019-02-04 15:05:37 -05:00
|
|
|
|
2013-10-25 13:25:02 -04:00
|
|
|
described_class.new(post2).flag_sockpuppet_users
|
2019-02-04 15:05:37 -05:00
|
|
|
|
|
|
|
expect(PostAction.where(user: system, post: post2, post_action_type_id: spam).exists?).to eq(
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
expect(
|
|
|
|
PostAction.where(user: system, post: first_post, post_action_type_id: spam).exists?,
|
|
|
|
).to eq(false)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't create a flag if user is nil on first post" do
|
|
|
|
post1.user_id = nil
|
|
|
|
post1.save
|
|
|
|
described_class.new(post2).flag_sockpuppet_users
|
2019-02-04 15:05:37 -05:00
|
|
|
|
|
|
|
expect(PostAction.where(user: system, post: post2, post_action_type_id: spam).exists?).to eq(
|
|
|
|
true,
|
|
|
|
)
|
|
|
|
expect(PostAction.where(user: system, post: post1, post_action_type_id: spam).exists?).to eq(
|
|
|
|
false,
|
|
|
|
)
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
2020-04-01 08:20:45 -04:00
|
|
|
|
|
|
|
it "doesn't flag the first post if it was already rejected by staff before" do
|
|
|
|
flagged_post =
|
|
|
|
Fabricate(
|
|
|
|
:reviewable_flagged_post,
|
|
|
|
target: post1,
|
|
|
|
status: Reviewable.statuses[:rejected],
|
|
|
|
target_created_by: post1.user,
|
|
|
|
)
|
|
|
|
|
|
|
|
described_class.new(post2).perform
|
|
|
|
|
2021-12-08 12:12:24 -05:00
|
|
|
expect(flagged_post.reload).to be_rejected
|
2020-04-01 08:20:45 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it "doesn't flag the post if another post of the same user was rejected by staff before" do
|
|
|
|
another_post = Fabricate(:post, user: user1)
|
|
|
|
flagged_post =
|
|
|
|
Fabricate(
|
|
|
|
:reviewable_flagged_post,
|
|
|
|
target: another_post,
|
|
|
|
status: Reviewable.statuses[:rejected],
|
|
|
|
target_created_by: another_post.user,
|
|
|
|
)
|
|
|
|
|
|
|
|
described_class.new(post2).perform
|
|
|
|
|
|
|
|
expect(ReviewableFlaggedPost.where(target_created_by: user1).count).to eq(1)
|
|
|
|
end
|
2013-10-25 13:25:02 -04:00
|
|
|
end
|
|
|
|
end
|