FEATURE: Support anonymizing a user's IP addresses
This commit is contained in:
parent
93b40d5e59
commit
e21a4ce1dd
|
@ -2,20 +2,23 @@ class UserAnonymizer
|
|||
|
||||
attr_reader :user_history
|
||||
|
||||
def initialize(user, actor = nil)
|
||||
# opts:
|
||||
# anonymize_ip - an optional new IP to update their logs with
|
||||
def initialize(user, actor = nil, opts = nil)
|
||||
@user = user
|
||||
@actor = actor
|
||||
@user_history = nil
|
||||
@opts = opts || {}
|
||||
end
|
||||
|
||||
def self.make_anonymous(user, actor = nil)
|
||||
self.new(user, actor).make_anonymous
|
||||
def self.make_anonymous(user, actor = nil, opts = nil)
|
||||
self.new(user, actor, opts).make_anonymous
|
||||
end
|
||||
|
||||
def make_anonymous
|
||||
User.transaction do
|
||||
prev_email = @user.email
|
||||
prev_username = @user.username
|
||||
@prev_email = @user.email
|
||||
@prev_username = @user.username
|
||||
|
||||
if !UsernameChanger.change(@user, make_anon_username)
|
||||
raise "Failed to change username"
|
||||
|
@ -28,6 +31,11 @@ class UserAnonymizer
|
|||
@user.date_of_birth = nil
|
||||
@user.title = nil
|
||||
@user.uploaded_avatar_id = nil
|
||||
|
||||
if @opts.has_key?(:anonymize_ip)
|
||||
anonymize_ips(@opts[:anonymize_ip])
|
||||
end
|
||||
|
||||
@user.save
|
||||
|
||||
options = @user.user_option
|
||||
|
@ -60,8 +68,8 @@ class UserAnonymizer
|
|||
}
|
||||
|
||||
if SiteSetting.log_anonymizer_details?
|
||||
history_details[:email] = prev_email
|
||||
history_details[:details] = "username: #{prev_username}"
|
||||
history_details[:email] = @prev_email
|
||||
history_details[:details] = "username: #{@prev_username}"
|
||||
end
|
||||
|
||||
@user_history = UserHistory.create(history_details)
|
||||
|
@ -69,6 +77,8 @@ class UserAnonymizer
|
|||
@user
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def make_anon_username
|
||||
100.times do
|
||||
new_username = "anon#{(SecureRandom.random_number * 100000000).to_i}"
|
||||
|
@ -76,4 +86,30 @@ class UserAnonymizer
|
|||
end
|
||||
raise "Failed to generate an anon username"
|
||||
end
|
||||
|
||||
def ip_where(column = 'user_id')
|
||||
["#{column} = :user_id AND ip_address IS NOT NULL", user_id: @user.id]
|
||||
end
|
||||
|
||||
def anonymize_ips(new_ip)
|
||||
@user.ip_address = new_ip
|
||||
@user.registration_ip_address = new_ip
|
||||
|
||||
IncomingLink.where(ip_where('current_user_id')).update_all(ip_address: new_ip)
|
||||
ScreenedEmail.where(email: @prev_email).update_all(ip_address: new_ip)
|
||||
SearchLog.where(ip_where).update_all(ip_address: new_ip)
|
||||
TopicLinkClick.where(ip_where).update_all(ip_address: new_ip)
|
||||
TopicViewItem.where(ip_where).update_all(ip_address: new_ip)
|
||||
UserHistory.where(ip_where('acting_user_id')).update_all(ip_address: new_ip)
|
||||
UserProfileView.where(ip_where).update_all(ip_address: new_ip)
|
||||
|
||||
# UserHistory for delete_user logs the user's IP. Note this is quite ugly but we don't
|
||||
# have a better way of querying on details right now.
|
||||
UserHistory.where(
|
||||
"action = :action AND details LIKE 'id: #{@user.id}\n%'",
|
||||
action: UserHistory.actions[:delete_user]
|
||||
).update_all(ip_address: new_ip)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -2,10 +2,10 @@ require "rails_helper"
|
|||
|
||||
describe UserAnonymizer do
|
||||
|
||||
describe "make_anonymous" do
|
||||
let(:admin) { Fabricate(:admin) }
|
||||
let(:user) { Fabricate(:user, username: "edward") }
|
||||
|
||||
describe "make_anonymous" do
|
||||
let(:user) { Fabricate(:user, username: "edward") }
|
||||
subject(:make_anonymous) { described_class.make_anonymous(user, admin) }
|
||||
|
||||
it "changes username" do
|
||||
|
@ -157,4 +157,75 @@ describe UserAnonymizer do
|
|||
|
||||
end
|
||||
|
||||
describe "anonymize_ip" do
|
||||
let(:old_ip) { "1.2.3.4" }
|
||||
let(:anon_ip) { "0.0.0.0" }
|
||||
let(:user) { Fabricate(:user, ip_address: old_ip, registration_ip_address: old_ip) }
|
||||
let(:post) { Fabricate(:post) }
|
||||
let(:topic) { post.topic }
|
||||
|
||||
it "doesn't anonymize ips by default" do
|
||||
UserAnonymizer.make_anonymous(user, admin)
|
||||
expect(user.ip_address).to eq(old_ip)
|
||||
end
|
||||
|
||||
it "is called if you pass an option" do
|
||||
UserAnonymizer.make_anonymous(user, admin, anonymize_ip: anon_ip)
|
||||
user.reload
|
||||
expect(user.ip_address).to eq(anon_ip)
|
||||
end
|
||||
|
||||
it "exhaustively replaces all user ips" do
|
||||
link = IncomingLink.create!(current_user_id: user.id, ip_address: old_ip, post_id: post.id)
|
||||
|
||||
screened_email = ScreenedEmail.create!(email: user.email, ip_address: old_ip)
|
||||
|
||||
search_log = SearchLog.create!(
|
||||
term: 'wat',
|
||||
search_type: SearchLog.search_types[:header],
|
||||
user_id: user.id,
|
||||
ip_address: old_ip
|
||||
)
|
||||
|
||||
topic_link = TopicLink.create!(
|
||||
user_id: admin.id,
|
||||
topic_id: topic.id,
|
||||
url: 'https://discourse.org',
|
||||
domain: 'discourse.org'
|
||||
)
|
||||
|
||||
topic_link_click = TopicLinkClick.create!(
|
||||
topic_link_id: topic_link.id,
|
||||
user_id: user.id,
|
||||
ip_address: old_ip
|
||||
)
|
||||
|
||||
user_profile_view = UserProfileView.create!(
|
||||
user_id: user.id,
|
||||
user_profile_id: admin.user_profile.id,
|
||||
ip_address: old_ip,
|
||||
viewed_at: Time.now
|
||||
)
|
||||
|
||||
TopicViewItem.create!(topic_id: topic.id, user_id: user.id, ip_address: old_ip, viewed_at: Time.now)
|
||||
delete_history = StaffActionLogger.new(admin).log_user_deletion(user)
|
||||
user_history = StaffActionLogger.new(user).log_backup_create
|
||||
|
||||
UserAnonymizer.make_anonymous(user, admin, anonymize_ip: anon_ip)
|
||||
expect(user.registration_ip_address).to eq(anon_ip)
|
||||
expect(link.reload.ip_address).to eq(anon_ip)
|
||||
expect(screened_email.reload.ip_address).to eq(anon_ip)
|
||||
expect(search_log.reload.ip_address).to eq(anon_ip)
|
||||
expect(topic_link_click.reload.ip_address).to eq(anon_ip)
|
||||
topic_view = TopicViewItem.where(topic_id: topic.id, user_id: user.id).first
|
||||
expect(topic_view.ip_address).to eq(anon_ip)
|
||||
expect(delete_history.reload.ip_address).to eq(anon_ip)
|
||||
expect(user_history.reload.ip_address).to eq(anon_ip)
|
||||
expect(user_profile_view.reload.ip_address).to eq(anon_ip)
|
||||
|
||||
expect("failed").to eq("success")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue