def Login(self, request, context): """ Does the first step of the Login flow. The user is searched for using their id, username, or email. If the user does not exist, returns a LOGIN_NO_SUCH_USER. If the user has a password, returns NEED_PASSWORD. If the user exists but does not have a password, generates a login token, send it in the email and returns SENT_LOGIN_EMAIL. """ logging.debug(f"Attempting login for {request.user=}") with session_scope(self._Session) as session: # Gets user by one of id/username/email or None if not found user = get_user_by_field(session, request.user) if user: if user.hashed_password is not None: logging.debug(f"Found user with password") return auth_pb2.LoginRes(next_step=auth_pb2.LoginRes.LoginStep.NEED_PASSWORD) else: logging.debug(f"Found user without password, sending login email") login_token, expiry_text = new_login_token(session, user) send_login_email(user, login_token, expiry_text) return auth_pb2.LoginRes(next_step=auth_pb2.LoginRes.LoginStep.SENT_LOGIN_EMAIL) else: # user not found logging.debug(f"Didn't find user") return auth_pb2.LoginRes(next_step=auth_pb2.LoginRes.LoginStep.INVALID_USER)
def test_login_email_full(db): user, api_token = generate_user() user_email = user.email with session_scope() as session: login_token, expiry_text = new_login_token(session, user) send_login_email(user, login_token, expiry_text) token = login_token.token def mock_print_dev_email(sender_name, sender_email, recipient, subject, plain, html): assert recipient == user.email assert "login" in subject.lower() assert login_token.token in plain assert login_token.token in html return print_dev_email(sender_name, sender_email, recipient, subject, plain, html) with patch("couchers.jobs.handlers.print_dev_email", mock_print_dev_email): process_job() with session_scope() as session: assert session.query(BackgroundJob).filter( BackgroundJob.state == BackgroundJobState.completed).count() == 1 assert session.query(BackgroundJob).filter( BackgroundJob.state != BackgroundJobState.completed).count() == 0
def test_login_email(db): user, api_token = generate_user() with session_scope() as session: login_token, expiry_text = new_login_token(session, user) with patch("couchers.email.queue_email") as mock: send_login_email(user, login_token, expiry_text) assert mock.call_count == 1 (sender_name, sender_email, recipient, subject, plain, html), _ = mock.call_args assert recipient == user.email assert "login" in subject.lower() assert login_token.token in plain assert login_token.token in html
def test_purge_login_tokens(db): user, api_token = generate_user() with session_scope() as session: login_token, expiry_text = new_login_token(session, user) login_token.expiry = func.now() assert session.query(LoginToken).count() == 1 queue_job(BackgroundJobType.purge_login_tokens, empty_pb2.Empty()) process_job() with session_scope() as session: assert session.query(LoginToken).count() == 0 with session_scope() as session: assert session.query(BackgroundJob).filter( BackgroundJob.state == BackgroundJobState.completed).count() == 1 assert session.query(BackgroundJob).filter( BackgroundJob.state != BackgroundJobState.completed).count() == 0
def test_login_email(db): user, api_token = generate_user(db) message_id = random_hex(64) with session_scope(db) as session: login_token, expiry_text = new_login_token(session, user) @create_autospec def mock_send_email(sender_name, sender_email, recipient, subject, plain, html): assert recipient == user.email assert "login" in subject.lower() assert login_token.token in plain assert login_token.token in html return message_id with patch("couchers.email.send_email", mock_send_email) as mock: send_login_email(user, login_token, expiry_text) assert mock.call_count == 1