Skip to content

Commit

Permalink
fixes check_other_registrations
Browse files Browse the repository at this point in the history
  • Loading branch information
pcrespov committed Dec 8, 2022
1 parent c2e638f commit 81fbd9f
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,12 @@
Json,
PositiveInt,
ValidationError,
parse_obj_as,
parse_raw_as,
validator,
)
from servicelib.mimetype_constants import MIMETYPE_APPLICATION_JSON
from yarl import URL

from ..db_models import UserStatus
from ._confirmation import (
ConfirmationAction,
get_expiration_date,
Expand All @@ -34,6 +32,7 @@
from ._constants import MSG_EMAIL_EXISTS
from .settings import LoginOptions
from .storage import AsyncpgStorage, ConfirmationTokenDict
from .utils import CONFIRMATION_PENDING

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -75,55 +74,45 @@ def ensure_enum(cls, v):
}


def validate_email(email):
try:
parse_obj_as(EmailStr, email)
except ValidationError as err:
raise web.HTTPUnprocessableEntity(
reason="Invalid email", content_type=MIMETYPE_APPLICATION_JSON
) from err
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422


async def validate_registration(
async def check_other_registrations(
email: str,
db: AsyncpgStorage,
cfg: LoginOptions,
) -> None:
# email : required & formats
# password: required & secure[min length, ...]
#
# NOTE: Extra requirements on passwords
# SEE https://github.com/ITISFoundation/osparc-simcore/issues/2480
#

# The email is already taken
if user := await db.get_user({"email": email}):
if (
user["status"] == UserStatus.CONFIRMATION_PENDING.value
and (
_confirmation := await db.get_confirmation(
filter_dict={
"user": user,
"action": ConfirmationAction.REGISTRATION.value,
}
)
user = await db.get_user({"email": email})
if not user:
# The email is already taken

# RULE: drop_previous_registration
# An unconfirmed account w/o confirmation or w/ an expired confirmation
# will get deleted and the email can be overtaken by
# this new registration
#
if user["status"] == CONFIRMATION_PENDING:
_confirmation = await db.get_confirmation(
filter_dict={
"user": user,
"action": ConfirmationAction.REGISTRATION.value,
}
)
and is_confirmation_expired(cfg, _confirmation)
):
#
# An unconfirmed account with an expired confirmation
# will get deleted and the email is associated to this new registration
#
await db.delete_confirmation_and_user(user=user, confirmation=_confirmation)

log.warning(
"Re-registration of %s with expired %s"
"Deleting user and proceeding to a new registration",
f"{user=}",
f"{_confirmation=}",
drop_previous_registration = not _confirmation or is_confirmation_expired(
cfg, _confirmation
)
return
if drop_previous_registration:
if not _confirmation:
await db.delete_user(user=user)
else:
await db.delete_confirmation_and_user(
user=user, confirmation=_confirmation
)

log.warning(
"Re-registration of %s with expired %s"
"Deleting user and proceeding to a new registration",
f"{user=}",
f"{_confirmation=}",
)
return

raise web.HTTPConflict(
reason=MSG_EMAIL_EXISTS, content_type=MIMETYPE_APPLICATION_JSON
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from ._confirmation import make_confirmation_link
from ._constants import MSG_2FA_CODE_SENT, MSG_CANT_SEND_MAIL
from ._models import InputSchema, check_confirm_password_match
from ._registration import check_and_consume_invitation, validate_registration
from ._registration import check_and_consume_invitation, check_other_registrations
from ._security import login_granted_response
from .settings import (
LoginOptions,
Expand Down Expand Up @@ -86,7 +86,7 @@ async def register(request: web.Request):

registration = await parse_request_body_as(RegisterBody, request)

await validate_registration(email=registration.email, db=db, cfg=cfg)
await check_other_registrations(email=registration.email, db=db, cfg=cfg)

expires_at = None # = does not expire
if settings.LOGIN_REGISTRATION_INVITATION_REQUIRED:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,7 @@ async def get_confirmation(self, filter_dict) -> Optional[ConfirmationTokenDict]
filter_dict["user_id"] = filter_dict.pop("user")["id"]
async with self.pool.acquire() as conn:
confirmation = await _sql.find_one(conn, self.confirm_tbl, filter_dict)
return (
ConfirmationTokenDict(**confirmation) if confirmation else confirmation
)
return ConfirmationTokenDict(**confirmation) if confirmation else None

async def delete_confirmation(self, confirmation: ConfirmationTokenDict):
async with self.pool.acquire() as conn:
Expand Down

0 comments on commit 81fbd9f

Please sign in to comment.