示例#1
0
    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)
示例#2
0
    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 or has been deleted, throws a NOT_FOUND rpc error.

        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.
        """
        logger.debug(f"Attempting login for {request.user=}")
        with session_scope() as session:
            # if the user is banned, they can get past this but get an error later in login flow
            user = session.execute(
                select(User).where_username_or_email(request.user).where(
                    ~User.is_deleted)).scalar_one_or_none()
            if user:
                if user.has_password:
                    logger.debug(f"Found user with password")
                    return auth_pb2.LoginRes(
                        next_step=auth_pb2.LoginRes.LoginStep.NEED_PASSWORD)
                else:
                    logger.debug(
                        f"Found user without password, sending login email")
                    send_login_email(session, user)
                    return auth_pb2.LoginRes(
                        next_step=auth_pb2.LoginRes.LoginStep.SENT_LOGIN_EMAIL)
            else:  # user not found
                logger.debug(f"Didn't find user")
                context.abort(grpc.StatusCode.NOT_FOUND, errors.USER_NOT_FOUND)
示例#3
0
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
示例#4
0
def test_login_email_full(db):
    user, api_token = generate_user()
    user_email = user.email

    with session_scope() as session:
        login_token = send_login_email(session, user)

        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.execute(
            select(func.count()).select_from(BackgroundJob).where(
                BackgroundJob.state ==
                BackgroundJobState.completed)).scalar_one() == 1)
        assert (session.execute(
            select(func.count()).select_from(BackgroundJob).where(
                BackgroundJob.state != BackgroundJobState.completed)).
                scalar_one() == 0)
示例#5
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
示例#6
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