diff --git a/libweasyl/alembic/versions/63baa2713e72_remove_signup_birthdate_column.py b/libweasyl/alembic/versions/63baa2713e72_remove_signup_birthdate_column.py new file mode 100644 index 000000000..862ffa55a --- /dev/null +++ b/libweasyl/alembic/versions/63baa2713e72_remove_signup_birthdate_column.py @@ -0,0 +1,22 @@ +"""Remove signup birthdate column + +Revision ID: 63baa2713e72 +Revises: 57171ee9e989 +Create Date: 2024-08-21 23:50:18.122609 + +""" + +# revision identifiers, used by Alembic. +revision = '63baa2713e72' +down_revision = '57171ee9e989' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + op.drop_column('logincreate', 'birthday') + + +def downgrade(): + op.add_column('logincreate', sa.Column('birthday', sa.INTEGER(), autoincrement=False, nullable=True)) diff --git a/libweasyl/models/tables.py b/libweasyl/models/tables.py index 40c14f80f..e2f6584aa 100644 --- a/libweasyl/models/tables.py +++ b/libweasyl/models/tables.py @@ -350,7 +350,6 @@ def default_fkey(*args, **kwargs): Column('login_name', String(length=40), nullable=False, unique=True), Column('hashpass', String(length=100), nullable=False), Column('email', String(length=100), nullable=False, unique=True), - Column('birthday', WeasylTimestampColumn(), nullable=True), Column('created_at', TIMESTAMP(timezone=True), nullable=False, server_default=func.now()), # Used to determine if a record is invalid for purposes of plausible deniability of email addresses # AKA, create a logincreate entry if an in-use email address is provided, thus preserving the effect of diff --git a/weasyl/controllers/user.py b/weasyl/controllers/user.py index a0037422b..f503e9927 100644 --- a/weasyl/controllers/user.py +++ b/weasyl/controllers/user.py @@ -186,8 +186,7 @@ def signup_get_(request): @token_checked def signup_post_(request): form = request.web_input( - username="", password="", email="", - day="", month="", year="") + username="", password="", email="") login.create(form) return Response(define.errorpage( diff --git a/weasyl/login.py b/weasyl/login.py index e46b46d69..0d312cde6 100644 --- a/weasyl/login.py +++ b/weasyl/login.py @@ -1,7 +1,6 @@ import os from io import open -import arrow import bcrypt from publicsuffixlist import PublicSuffixList from sqlalchemy.sql.expression import select @@ -204,27 +203,11 @@ def create(form): # Normalize form data username = clean_display_name(form.username) sysname = d.get_sysname(username) - email = emailer.normalize_address(form.email) - - # TODO: remove birth date check after checkbox-only form has been deployed for a while password = form.password - if form.day and form.month and form.year: - try: - birthday = arrow.Arrow(int(form.year), int(form.month), int(form.day)) - except ValueError: - raise WeasylError("birthdayInvalid") - - if d.age_in_years(birthday) < 13: - raise WeasylError("birthdayInvalid") - else: - birthday = None - - if "age" in form and form.age != "13+": - raise WeasylError("birthdayInvalid") # Check invalid form data - if birthday is None and "age" not in form: + if "age" not in form or form.age != "13+": raise WeasylError("birthdayInvalid") if not password_secure(password): raise WeasylError("passwordInsecure") @@ -251,7 +234,6 @@ def create(form): "login_name": sysname, "hashpass": passhash(password), "email": email, - "birthday": birthday, }) # Send verification email @@ -268,7 +250,6 @@ def create(form): "login_name": sysname, "hashpass": passhash(password), "email": token, - "birthday": None, "invalid": True, # So we have a way for admins to determine which email address collided in the View Pending Accounts Page "invalid_email_addr": email, @@ -320,7 +301,6 @@ def verify(token, ip_address=None): }) db.execute(d.meta.tables["userinfo"].insert(), { "userid": userid, - "birthday": query.birthday, }) # Update logincreate records diff --git a/weasyl/test/login/test_create.py b/weasyl/test/login/test_create.py index 6fa75fe82..d162cb7f4 100644 --- a/weasyl/test/login/test_create.py +++ b/weasyl/test/login/test_create.py @@ -1,5 +1,4 @@ import pytest -import arrow from web.utils import Storage as Bag from weasyl import define as d @@ -16,92 +15,9 @@ @pytest.mark.usefixtures('db') -def test_DMY_not_integer_raises_birthdayInvalid_WeasylError(): - # Check for failure state if 'day' is not an integer, e.g., string +def test_age_minimum(): form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='test', month='31', year='1942') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'month' is not an integer, e.g., string - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='test', year='1942') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'year' is not an integer, e.g., string - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='31', year='test') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - -@pytest.mark.usefixtures('db') -def test_DMY_out_of_valid_ranges_raises_birthdayInvalid_WeasylError(): - # Check for failure state if 'day' is not an valid day e.g., 42 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='42', month='12', year='2000') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'month' is not an valid month e.g., 42 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='42', year='2000') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'year' is not an valid year e.g., -1 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='12', year='-1') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - -@pytest.mark.usefixtures('db') -def test_DMY_missing_raises_birthdayInvalid_WeasylError(): - # Check for failure state if 'year' is not an valid year e.g., -1 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day=None, month='12', year='2000') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'year' is not an valid year e.g., -1 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month=None, year='2000') - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - # Check for failure state if 'year' is not an valid year e.g., -1 - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='12', year=None) - with pytest.raises(WeasylError) as err: - login.create(form) - assert 'birthdayInvalid' == err.value.value - - -@pytest.mark.usefixtures('db') -def test_under_13_age_raises_birthdayInvalid_WeasylError(): - # Check for failure state if computed birthday is <13 years old - form = Bag(username=user_name, password='', - email='test@weasyl.com', - day='12', month='12', year=arrow.utcnow().year - 11) + email='test@weasyl.com') with pytest.raises(WeasylError) as err: login.create(form) assert 'birthdayInvalid' == err.value.value @@ -112,7 +28,7 @@ def test_passwords_must_be_of_sufficient_length(): password = "tooShort" form = Bag(username=user_name, password=password, email='foo', - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") # Insecure length with pytest.raises(WeasylError) as err: login.create(form) @@ -130,7 +46,7 @@ def test_passwords_must_be_of_sufficient_length(): def test_create_fails_if_email_is_invalid(): form = Bag(username=user_name, password='0123456789', email=';--', - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'emailInvalid' == err.value.value @@ -146,7 +62,7 @@ def test_create_fails_if_another_account_has_email_linked_to_their_account(): db_utils.create_user(username=user_name, email_addr=email_addr) form = Bag(username="user", password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) query = d.engine.scalar(""" SELECT username FROM logincreate WHERE username = %(username)s AND invalid IS TRUE @@ -167,11 +83,10 @@ def test_create_fails_if_pending_account_has_same_email(): "login_name": "existing", "hashpass": login.passhash(raw_password), "email": email_addr, - "birthday": arrow.Arrow(2000, 1, 1), }) form = Bag(username="test", password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) query = d.engine.scalar(""" SELECT username FROM logincreate WHERE username = %(username)s AND invalid IS TRUE @@ -183,7 +98,7 @@ def test_create_fails_if_pending_account_has_same_email(): def test_username_cant_be_blank_or_have_semicolon(): form = Bag(username='...', password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'usernameInvalid' == err.value.value @@ -199,7 +114,7 @@ def test_username_cant_be_blank_or_have_semicolon(): def test_create_fails_if_username_is_a_prohibited_name(): form = Bag(username='testloginsuite', password='0123456789', email='test@weasyl.com', - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") prohibited_names = ["admin", "administrator", "mod", "moderator", "weasyl", "weasyladmin", "weasylmod", "staff", "security"] for name in prohibited_names: @@ -214,7 +129,7 @@ def test_usernames_must_be_unique(): db_utils.create_user(username=user_name, email_addr="test_2@weasyl.com") form = Bag(username=user_name, password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'usernameExists' == err.value.value @@ -228,11 +143,10 @@ def test_usernames_cannot_match_pending_account_usernames(): "login_name": user_name, "hashpass": login.passhash(raw_password), "email": "test0003@weasyl.com", - "birthday": arrow.Arrow(2000, 1, 1), }) form = Bag(username=user_name, password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'usernameExists' == err.value.value @@ -244,7 +158,7 @@ def test_username_cannot_match_an_active_alias(): d.engine.execute("INSERT INTO useralias VALUES (%(userid)s, %(username)s, 'p')", userid=user_id, username=user_name) form = Bag(username=user_name, password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'usernameExists' == err.value.value @@ -254,7 +168,7 @@ def test_username_cannot_match_an_active_alias(): def test_verify_correct_information_creates_account(): form = Bag(username=user_name, password='0123456789', email=email_addr, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) # This record should exist when this function completes successfully assert d.engine.scalar( @@ -278,7 +192,7 @@ def test_create_fails_if_email_domain_is_blacklisted(self): blacklisted_email = "test@blacklisted.com" form = Bag(username=user_name, password='0123456789', email=blacklisted_email, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'emailBlacklisted' == err.value.value @@ -299,7 +213,7 @@ def test_verify_subdomains_of_blocked_sites_blocked(self): blacklisted_email = "test@subdomain.blacklisted.com" form = Bag(username=user_name, password='0123456789', email=blacklisted_email, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'emailBlacklisted' == err.value.value @@ -308,7 +222,7 @@ def test_verify_subdomains_of_blocked_sites_blocked(self): blacklisted_email = "test@mail.sub.sharklasers.com" form = Bag(username=user_name, password='0123456789', email=blacklisted_email, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'emailBlacklisted' == err.value.value @@ -317,7 +231,7 @@ def test_verify_subdomains_of_blocked_sites_blocked(self): blacklisted_email = "test@sharklasers.com.sharklasers.com" form = Bag(username=user_name, password='0123456789', email=blacklisted_email, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") with pytest.raises(WeasylError) as err: login.create(form) assert 'emailBlacklisted' == err.value.value @@ -337,17 +251,17 @@ def test_similarly_named_domains_are_not_blocked(self): mail = "test@notblacklisted.com" form = Bag(username=user_name, password='0123456789', email=mail, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) mail = "test@also.notblacklisted.com" form = Bag(username=user_name + "1", password='0123456789', email=mail, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) mail = "test@blacklisted.com.notblacklisted.com" form = Bag(username=user_name + "2", password='0123456789', email=mail, - day='12', month='12', year=arrow.utcnow().year - 19) + age="13+") login.create(form) diff --git a/weasyl/test/login/test_get_account_verification_token.py b/weasyl/test/login/test_get_account_verification_token.py index be97f8a99..9296de856 100644 --- a/weasyl/test/login/test_get_account_verification_token.py +++ b/weasyl/test/login/test_get_account_verification_token.py @@ -1,5 +1,4 @@ import pytest -import arrow from weasyl import login from weasyl import define as d @@ -21,7 +20,6 @@ def test_acct_verif_token_returned_if_email_provided_to_function(): "login_name": user_name, "hashpass": login.passhash(raw_password), "email": email_addr, - "birthday": arrow.Arrow(2000, 1, 1), }) acct_verification_token = login.get_account_verification_token(email=email_addr, username=None) assert token == acct_verification_token @@ -35,7 +33,6 @@ def test_acct_verif_token_returned_if_username_provided_to_function(): "login_name": user_name, "hashpass": login.passhash(raw_password), "email": email_addr, - "birthday": arrow.Arrow(2000, 1, 1), }) acct_verification_token = login.get_account_verification_token(email=None, username=user_name) assert token == acct_verification_token diff --git a/weasyl/test/login/test_verify.py b/weasyl/test/login/test_verify.py index 59558d589..fb3e941be 100644 --- a/weasyl/test/login/test_verify.py +++ b/weasyl/test/login/test_verify.py @@ -1,5 +1,4 @@ import pytest -import arrow from weasyl import login from weasyl import define as d @@ -18,7 +17,6 @@ def _create_pending_account(invalid=False): "login_name": username, "hashpass": login.passhash('0123456789'), "email": email, - "birthday": arrow.Arrow(2000, 1, 1), "invalid": invalid, })