users: track logins, signups, and other user events.
Add tracking of certain important user actions. These events include: * Logins * Logouts * Failed login attempts * Account creations * Account deletions * Password reset requests * Password changes * Email address changes This is similar to the mod actions log, except for account activity related to a single user. The information tracked includes the user, the event type (login, logout, etc), the timestamp, the user's IP address, IP geolocation information, the user's browser user agent, and the user's session ID from their session cookie. This information is visible to mods only. This is done with three models. The UserEvent model tracks the event type (login, logout, password change, etc) and the user. The UserEvent is tied to a UserSession, which contains the user's IP address and browser metadata. Finally, the IpGeolocation model contains the geolocation information for IPs, including the city, country, ISP, and whether the IP is a proxy. This tracking will be used for a few purposes: * Letting users view their account history, to detect things like logins from unrecognized IPs, failed logins attempts, password changes, etc. * Rate limiting failed login attempts. * Detecting sockpuppet accounts using their login history. * Detecting unauthorized account sharing.
This commit is contained in:
@@ -89,6 +89,7 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal("abc@ogres.net", @user.reload.email_address.address)
|
||||
assert_equal(false, @user.email_address.is_verified)
|
||||
assert_enqueued_email_with UserMailer, :email_change_confirmation, args: [@user], queue: "default"
|
||||
assert_equal(true, @user.user_events.email_change.exists?)
|
||||
end
|
||||
|
||||
should "create a new address" do
|
||||
@@ -102,6 +103,7 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal("abc@ogres.net", @user.reload.email_address.address)
|
||||
assert_equal(false, @user.reload.email_address.is_verified)
|
||||
assert_enqueued_email_with UserMailer, :email_change_confirmation, args: [@user], queue: "default"
|
||||
assert_equal(true, @user.user_events.email_change.exists?)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -112,6 +114,7 @@ class EmailsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_response :success
|
||||
assert_equal("bob@ogres.net", @user.reload.email_address.address)
|
||||
assert_no_emails
|
||||
assert_equal(false, @user.user_events.email_change.exists?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,18 +18,22 @@ module Maintenance
|
||||
context "#destroy" do
|
||||
should "delete the user when given the correct password" do
|
||||
delete_auth maintenance_user_deletion_path, @user, params: { user: { password: "password" }}
|
||||
|
||||
assert_redirected_to posts_path
|
||||
assert_equal(true, @user.reload.is_deleted?)
|
||||
assert_equal("Your account has been deactivated", flash[:notice])
|
||||
assert_nil(session[:user_id])
|
||||
assert_equal(true, @user.user_events.user_deletion.exists?)
|
||||
end
|
||||
|
||||
should "not delete the user when given an incorrect password" do
|
||||
delete_auth maintenance_user_deletion_path, @user, params: { user: { password: "hunter2" }}
|
||||
|
||||
assert_redirected_to maintenance_user_deletion_path
|
||||
assert_equal(false, @user.reload.is_deleted?)
|
||||
assert_equal("Password is incorrect", flash[:notice])
|
||||
assert_equal(@user.id, session[:user_id])
|
||||
assert_equal(false, @user.user_events.user_deletion.exists?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,6 +16,7 @@ class PasswordResetsControllerTest < ActionDispatch::IntegrationTest
|
||||
|
||||
assert_redirected_to new_session_path
|
||||
assert_enqueued_email_with UserMailer, :password_reset, args: [@user], queue: "default"
|
||||
assert_equal(true, @user.user_events.password_reset.exists?)
|
||||
end
|
||||
|
||||
should "should fail if the user doesn't have a verified email address" do
|
||||
|
||||
@@ -20,6 +20,7 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to @user
|
||||
assert_equal(false, @user.reload.authenticate_password("12345"))
|
||||
assert_equal(@user, @user.authenticate_password("abcde"))
|
||||
assert_equal(true, @user.user_events.password_change.exists?)
|
||||
end
|
||||
|
||||
should "update the password when given a valid login key" do
|
||||
@@ -29,6 +30,7 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to @user
|
||||
assert_equal(false, @user.reload.authenticate_password("12345"))
|
||||
assert_equal(@user, @user.authenticate_password("abcde"))
|
||||
assert_equal(true, @user.user_events.password_change.exists?)
|
||||
end
|
||||
|
||||
should "allow the site owner to change the password of other users" do
|
||||
@@ -55,6 +57,7 @@ class PasswordsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_response :success
|
||||
assert_equal(@user, @user.reload.authenticate_password("12345"))
|
||||
assert_equal(false, @user.authenticate_password("abcde"))
|
||||
assert_equal(false, @user.user_events.password_change.exists?)
|
||||
end
|
||||
|
||||
should "not update the password when password confirmation fails for the new password" do
|
||||
|
||||
@@ -20,11 +20,20 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_redirected_to posts_path
|
||||
assert_equal(@user.id, session[:user_id])
|
||||
assert_not_nil(@user.reload.last_ip_addr)
|
||||
assert_equal(true, @user.user_events.login.exists?)
|
||||
end
|
||||
|
||||
should "not log the user in when given an incorrect password" do
|
||||
post session_path, params: { name: @user.name, password: "wrong"}
|
||||
|
||||
assert_response 401
|
||||
assert_nil(nil, session[:user_id])
|
||||
assert_equal(true, @user.user_events.failed_login.exists?)
|
||||
end
|
||||
|
||||
should "not log the user in when given an incorrect username" do
|
||||
post session_path, params: { name: "dne", password: "password" }
|
||||
|
||||
assert_response 401
|
||||
assert_nil(nil, session[:user_id])
|
||||
end
|
||||
@@ -66,11 +75,18 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
context "destroy action" do
|
||||
should "clear the session" do
|
||||
setup do
|
||||
delete_auth session_path, @user
|
||||
end
|
||||
|
||||
should "clear the session" do
|
||||
assert_redirected_to posts_path
|
||||
assert_nil(session[:user_id])
|
||||
end
|
||||
|
||||
should "generate a logout event" do
|
||||
assert_equal(true, @user.user_events.logout.exists?)
|
||||
end
|
||||
end
|
||||
|
||||
context "sign_out action" do
|
||||
|
||||
@@ -260,6 +260,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(User.last, User.last.authenticate_password("xxxxx1"))
|
||||
assert_nil(User.last.email_address)
|
||||
assert_no_enqueued_emails
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "create a user with a valid email" do
|
||||
@@ -270,6 +271,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(User.last, User.last.authenticate_password("xxxxx1"))
|
||||
assert_equal("webmaster@danbooru.donmai.us", User.last.email_address.address)
|
||||
assert_enqueued_email_with UserMailer, :welcome_user, args: [User.last], queue: "default"
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "not create a user with an invalid email" do
|
||||
@@ -307,6 +309,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(true, User.last.is_member?)
|
||||
assert_equal(false, User.last.is_restricted?)
|
||||
assert_equal(false, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "mark accounts created by already logged in users as restricted" do
|
||||
@@ -318,6 +321,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(false, User.last.is_member?)
|
||||
assert_equal(true, User.last.is_restricted?)
|
||||
assert_equal(true, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "mark users signing up from proxies as restricted" do
|
||||
@@ -330,6 +334,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(false, User.last.is_member?)
|
||||
assert_equal(true, User.last.is_restricted?)
|
||||
assert_equal(true, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "mark users signing up from a partial banned IP as restricted" do
|
||||
@@ -344,6 +349,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(true, User.last.requires_verification)
|
||||
assert_equal(1, @ip_ban.reload.hit_count)
|
||||
assert(@ip_ban.last_hit_at > 1.minute.ago)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "not mark users signing up from non-proxies as restricted" do
|
||||
@@ -356,6 +362,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(true, User.last.is_member?)
|
||||
assert_equal(false, User.last.is_restricted?)
|
||||
assert_equal(false, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "mark accounts registered from an IPv4 address recently used for another account as restricted" do
|
||||
@@ -368,6 +375,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(false, User.last.is_member?)
|
||||
assert_equal(true, User.last.is_restricted?)
|
||||
assert_equal(true, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
|
||||
should "not mark users signing up from localhost as restricted" do
|
||||
@@ -379,6 +387,7 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
|
||||
assert_equal(true, User.last.is_member?)
|
||||
assert_equal(false, User.last.is_restricted?)
|
||||
assert_equal(false, User.last.requires_verification)
|
||||
assert_equal(true, User.last.user_events.user_creation.exists?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user