Files
danbooru/test/unit/user_test.rb
evazion a160a3acce users: add stricter username rules.
Add stricter username rules:

* Only allow usernames to contain basic letters, numbers, CJK characters, underscores, dashes and periods.
* Don't allow names to start or end with punctuation.
* Don't allow names to have multiple underscores in a row.
* Don't allow active users to have names that look like deleted users (e.g. "user_1234").
* Don't allow emoji or any other Unicode characters except for Chinese, Japanese, and Korean
  characters. CJK characters are currently grandfathered in but will be disallowed in the future.

Users with an invalid name will be shown a permanent sitewide banner until they change their name.
2022-03-05 01:08:53 -06:00

315 lines
10 KiB
Ruby

require 'test_helper'
class UserTest < ActiveSupport::TestCase
def assert_promoted_to(new_level, user, promoter)
user.promote_to!(new_level, promoter)
assert_equal(new_level, user.reload.level)
end
def assert_not_promoted_to(new_level, user, promoter)
assert_raise(User::PrivilegeError) do
user.promote_to!(new_level, promoter)
end
assert_not_equal(new_level, user.reload.level)
end
context "A user" do
setup do
@user = FactoryBot.create(:user)
CurrentUser.user = @user
CurrentUser.ip_addr = "127.0.0.1"
end
teardown do
CurrentUser.user = nil
CurrentUser.ip_addr = nil
end
context "promoting a user" do
setup do
@builder = create(:builder_user)
@mod = create(:moderator_user)
@admin = create(:admin_user)
@owner = create(:owner_user)
end
should "allow moderators to promote users up to builder level" do
assert_promoted_to(User::Levels::GOLD, @user, @mod)
assert_promoted_to(User::Levels::PLATINUM, @user, @mod)
assert_promoted_to(User::Levels::BUILDER, @user, @mod)
assert_not_promoted_to(User::Levels::MODERATOR, @user, @mod)
assert_not_promoted_to(User::Levels::ADMIN, @user, @mod)
assert_not_promoted_to(User::Levels::OWNER, @user, @mod)
end
should "allow admins to promote users up to moderator level" do
assert_promoted_to(User::Levels::GOLD, @user, @admin)
assert_promoted_to(User::Levels::PLATINUM, @user, @admin)
assert_promoted_to(User::Levels::BUILDER, @user, @admin)
assert_promoted_to(User::Levels::MODERATOR, @user, @admin)
assert_not_promoted_to(User::Levels::ADMIN, @user, @admin)
assert_not_promoted_to(User::Levels::OWNER, @user, @admin)
end
should "allow the owner to promote users up to admin level" do
assert_promoted_to(User::Levels::GOLD, @user, @owner)
assert_promoted_to(User::Levels::PLATINUM, @user, @owner)
assert_promoted_to(User::Levels::BUILDER, @user, @owner)
assert_promoted_to(User::Levels::MODERATOR, @user, @owner)
assert_promoted_to(User::Levels::ADMIN, @user, @owner)
assert_not_promoted_to(User::Levels::OWNER, @user, @owner)
end
should "not allow non-moderators to promote other users" do
assert_not_promoted_to(User::Levels::GOLD, @user, @builder)
assert_not_promoted_to(User::Levels::PLATINUM, @user, @builder)
assert_not_promoted_to(User::Levels::BUILDER, @user, @builder)
assert_not_promoted_to(User::Levels::MODERATOR, @user, @builder)
assert_not_promoted_to(User::Levels::ADMIN, @user, @builder)
assert_not_promoted_to(User::Levels::OWNER, @user, @builder)
end
should "not allow users to promote or demote other users at their rank or above" do
assert_not_promoted_to(User::Levels::ADMIN, create(:moderator_user), @mod)
assert_not_promoted_to(User::Levels::BUILDER, create(:moderator_user), @mod)
assert_not_promoted_to(User::Levels::OWNER, create(:admin_user), @admin)
assert_not_promoted_to(User::Levels::MODERATOR, create(:admin_user), @admin)
assert_not_promoted_to(User::Levels::ADMIN, create(:owner_user), @owner)
end
should "not allow users to promote themselves" do
assert_not_promoted_to(User::Levels::ADMIN, @mod, @mod)
assert_not_promoted_to(User::Levels::OWNER, @admin, @admin)
end
should "not allow users to demote themselves" do
assert_not_promoted_to(User::Levels::MEMBER, @mod, @mod)
assert_not_promoted_to(User::Levels::MEMBER, @admin, @admin)
assert_not_promoted_to(User::Levels::MEMBER, @owner, @owner)
end
should "create a neutral feedback" do
@user.promote_to!(User::Levels::GOLD, @mod)
assert_equal("You have been promoted to a Gold level account from Member.", @user.feedback.last.body)
end
should "send an automated dmail to the user" do
bot = FactoryBot.create(:user)
User.stubs(:system).returns(bot)
assert_difference("Dmail.count", 1) do
@user.promote_to!(User::Levels::GOLD, @admin)
end
assert(@user.dmails.exists?(from: bot, to: @user, title: "Your account has been updated"))
refute(@user.dmails.exists?(from: bot, to: @user, title: "Your user record has been updated"))
end
end
should "authenticate password" do
assert_equal(@user, @user.authenticate_password("password"))
assert_equal(false, @user.authenticate_password("password2"))
end
should "normalize its level" do
user = FactoryBot.create(:user, :level => User::Levels::OWNER)
assert(user.is_owner?)
assert(user.is_admin?)
assert(user.is_moderator?)
assert(user.is_gold?)
user = FactoryBot.create(:user, :level => User::Levels::ADMIN)
assert(!user.is_owner?)
assert(user.is_moderator?)
assert(user.is_gold?)
user = FactoryBot.create(:user, :level => User::Levels::MODERATOR)
assert(!user.is_admin?)
assert(user.is_moderator?)
assert(user.is_gold?)
user = FactoryBot.create(:user, :level => User::Levels::GOLD)
assert(!user.is_admin?)
assert(!user.is_moderator?)
assert(user.is_gold?)
user = FactoryBot.create(:user)
assert(!user.is_admin?)
assert(!user.is_moderator?)
assert(!user.is_gold?)
end
context "name" do
should "not contain whitespace" do
# U+2007: https://en.wikipedia.org/wiki/Figure_space
user = build(:user, name: "foo\u2007bar")
user.save
assert_equal(["Name can't contain whitespace"], user.errors.full_messages)
end
should "be less than 25 characters long" do
user = build(:user, name: "a"*25)
user.save
assert_equal(["Name must be less than 25 characters long"], user.errors.full_messages)
end
should "not contain a colon" do
user = build(:user, name: "a:b")
user.save
assert_equal(["Name can't contain ':'"], user.errors.full_messages)
end
should "not begin with an underscore" do
user = build(:user, name: "_x")
user.save
assert_equal(["Name can't start with '_'"], user.errors.full_messages)
end
should "not end with an underscore" do
user = build(:user, name: "x_")
user.save
assert_equal(["Name can't end with '_'"], user.errors.full_messages)
end
should "not contain consecutive underscores" do
user = build(:user, name: "x__y")
user.save
assert_equal(["Name can't contain multiple underscores in a row"], user.errors.full_messages)
end
should "not allow non-ASCII characters" do
user = build(:user, name: "Pokémon")
user.save
assert_equal(["Name must contain only basic letters or numbers"], user.errors.full_messages)
end
should "not be in the same format as a deleted user" do
user = build(:user, name: "user_1234")
user.save
assert_equal(["Name can't be the same as a deleted user"], user.errors.full_messages)
end
should "not allow blacklisted names" do
Danbooru.config.stubs(:user_name_blacklist).returns(["voldemort"])
user = build(:user, name: "voldemort42")
user.save
assert_equal(["Name is not allowed"], user.errors.full_messages)
end
end
context "searching for users by name" do
setup do
@miku = create(:user, name: "hatsune_miku")
end
should "be case-insensitive" do
assert_equal("hatsune_miku", User.normalize_name("Hatsune_Miku"))
assert_equal(@miku.id, User.find_by_name("Hatsune_Miku").id)
assert_equal(@miku.id, User.name_to_id("Hatsune_Miku"))
end
should "handle whitespace" do
assert_equal("hatsune_miku", User.normalize_name(" hatsune miku "))
assert_equal(@miku.id, User.find_by_name(" hatsune miku ").id)
assert_equal(@miku.id, User.name_to_id(" hatsune miku "))
end
should "return nil for nonexistent names" do
assert_nil(User.find_by_name("does_not_exist"))
assert_nil(User.name_to_id("does_not_exist"))
end
should "work for names containing asterisks or backslashes" do
@user1 = build(:user, name: "user*1")
@user2 = build(:user, name: "user*2")
@user3 = build(:user, name: "user\*3")
@user1.save(validate: false)
@user2.save(validate: false)
@user3.save(validate: false)
assert_equal(@user1.id, User.find_by_name("user*1").id)
assert_equal(@user2.id, User.find_by_name("user*2").id)
assert_equal(@user3.id, User.find_by_name("user\*3").id)
end
end
context "ip address" do
setup do
@user = FactoryBot.create(:user)
end
context "in the json representation" do
should "not appear" do
assert(@user.to_json !~ /addr/)
end
end
context "in the xml representation" do
should "not appear" do
assert(@user.to_xml !~ /addr/)
end
end
end
context "password" do
context "in the json representation" do
setup do
@user = FactoryBot.create(:user)
end
should "not appear" do
assert(@user.to_json !~ /password/)
end
end
context "in the xml representation" do
setup do
@user = FactoryBot.create(:user)
end
should "not appear" do
assert(@user.to_xml !~ /password/)
end
end
end
context "when searched by name" do
should "match wildcards" do
user1 = build(:user, name: "foo")
user2 = build(:user, name: "foo*bar")
user3 = build(:user, name: "bar\*baz")
user1.save(validate: false)
user2.save(validate: false)
user3.save(validate: false)
assert_equal([user2.id, user1.id], User.search(name: "foo*").map(&:id))
assert_equal([user2.id], User.search(name: "foo\*bar").map(&:id))
assert_equal([user3.id], User.search(name: "bar\\\*baz").map(&:id))
end
end
context "custom CSS" do
should "raise a validation error on invalid custom CSS" do
user = build(:user, custom_style: "}}}")
assert_equal(true, user.invalid?)
assert_match(/Custom CSS contains a syntax error/, user.errors[:base].first)
end
should "allow blank CSS" do
user = build(:user, custom_style: " ")
assert_equal(true, user.valid?)
end
end
end
end