diff --git a/bemani/data/config.py b/bemani/data/config.py index f2af3e0..5cf0c5a 100644 --- a/bemani/data/config.py +++ b/bemani/data/config.py @@ -83,6 +83,10 @@ class Server: def allow_raw_ids(self) -> bool: return bool(self.__config.get("server", {}).get("allow_raw_ids", False)) + @property + def allow_unlinked_signups(self) -> bool: + return bool(self.__config.get("server", {}).get("allow_unlinked_signups", False)) + @property def region(self) -> int: region = int(self.__config.get("server", {}).get("region", RegionConstants.USA)) diff --git a/bemani/frontend/account/account.py b/bemani/frontend/account/account.py index 4ac1c2c..a7667a3 100644 --- a/bemani/frontend/account/account.py +++ b/bemani/frontend/account/account.py @@ -210,22 +210,48 @@ def register() -> Response: error("Invalid card number!") return register_display(card_number, username, email) - # Now, see if this card ID exists already - userid = g.data.local.user.from_cardid(cardid) - if userid is None: - error("This card has not been used on the network yet!") - return register_display(card_number, username, email) + if g.config.server.allow_unlinked_signups: + # We only need to check if the card is in use already + # by another user, or if the PIN was invalid on a card + # the user is trying to claim. We don't need to verify + # that the card has been seen yet. + userid = g.data.local.user.from_cardid(cardid) + if userid is not None: + # Now, make sure this user doesn't already have an account + user = g.data.local.user.get_user(userid) + if user.username is not None or user.email is not None: + error("This card is already in use!") + return register_display(card_number, username, email) - # Now, make sure this user doesn't already have an account - user = g.data.local.user.get_user(userid) - if user.username is not None or user.email is not None: - error("This card is already in use!") - return register_display(card_number, username, email) + # Now, see if the pin is correct + if not g.data.local.user.validate_pin(userid, pin): + error("The entered PIN does not match the PIN on the card!") + return register_display(card_number, username, email) - # Now, see if the pin is correct - if not g.data.local.user.validate_pin(userid, pin): - error("The entered PIN does not match the PIN on the card!") - return register_display(card_number, username, email) + else: + # We need to make sure the PIN they proposed is at least + # valid, because we're going to create a card with this PIN. + if not valid_pin(pin, "card"): + error("Invalid PIN, must be exactly 4 digits!") + return register_display(card_number, username, email) + + else: + # Now, see if this card ID exists already + userid = g.data.local.user.from_cardid(cardid) + if userid is None: + error("This card has not been used on the network yet!") + return register_display(card_number, username, email) + + # Now, make sure this user doesn't already have an account + user = g.data.local.user.get_user(userid) + if user.username is not None or user.email is not None: + error("This card is already in use!") + return register_display(card_number, username, email) + + # Now, see if the pin is correct + if not g.data.local.user.validate_pin(userid, pin): + error("The entered PIN does not match the PIN on the card!") + return register_display(card_number, username, email) # Now, see if the username is valid if not valid_username(username): @@ -252,6 +278,14 @@ def register() -> Response: error("Password is not long enough!") return register_display(card_number, username, email) + if g.config.server.allow_unlinked_signups: + if userid is None: + userid = g.data.local.user.create_account(cardid, pin) + user = g.data.local.user.get_user(userid) + + if userid is None or user is None: + raise Exception("Logic error, shouldn't get to this point without a user!") + # Now, create the account. user.username = username user.email = email diff --git a/bemani/frontend/app.py b/bemani/frontend/app.py index b2c90d0..536089d 100644 --- a/bemani/frontend/app.py +++ b/bemani/frontend/app.py @@ -2,7 +2,7 @@ import mimetypes import os import re import traceback -from typing import Callable, Dict, Any, Optional, List +from typing import Callable, Dict, Any, Optional, List, Literal from react.jsx import JSXTransformer # type: ignore from flask import ( Flask, @@ -320,13 +320,13 @@ def valid_username(username: str) -> bool: return re.match(r"^[a-zA-Z0-9_]+$", username) is not None -def valid_pin(pin: str, type: str) -> bool: +def valid_pin(pin: str, type: Literal["card", "arcade"]) -> bool: if type == "card": return re.match(r"^\d\d\d\d$", pin) is not None elif type == "arcade": return re.match(r"^\d\d\d\d\d\d\d\d$", pin) is not None else: - return False + return False # type: ignore # Define useful functions for jnija2 @@ -356,6 +356,8 @@ def navigation() -> Dict[str, Any]: custom_config = {} if g.config.server.allow_raw_ids: custom_config["allow_raw_ids"] = True + if g.config.server.allow_unlinked_signups: + custom_config["allow_unlinked_signups"] = True # Look up the logged in user ID. try: diff --git a/bemani/frontend/templates/account/register.html b/bemani/frontend/templates/account/register.html index c30c1c2..2c858d2 100644 --- a/bemani/frontend/templates/account/register.html +++ b/bemani/frontend/templates/account/register.html @@ -5,19 +5,23 @@