"""Test the logic attached to a user.""" from unittest.mock import MagicMock from unittest.mock import Mock from faker import Faker import pytest import requests import rsa from sukimu import response from auth.logic import passwords from auth.logic import user from auth.models import user as user_model @pytest.fixture def random_user(clean=True): """Create a random user.""" fake = Faker() password = fake.password() current_user = user.create_user( fake.user_name(), password, fake.email(), clean=clean) return current_user, password def test_get_user_missing_identifier(): """Getting a user without providing username or email.""" response = user.get_user(None) assert not response.success assert response.errors.get('identifier') def test_get_user_by_username(monkeypatch, random_user): """Test getting a user by a username.""" current_user, password = random_user resp = user.get_user(current_user.login) assert resp.success assert resp.login == current_user.login def test_get_user_by_invalid_identifier(monkeypatch, random_user): """Test getting a user by a email.""" current_user, password = random_user resp = user.get_user('randomid') assert not resp.success def test_get_user_by_email(monkeypatch, random_user): """Test getting a user by a email.""" current_user, password = random_user spy = MagicMock() def query_2(**query): spy() if query.get('email__eq') == current_user.email: return [current_user.message] return [] monkeypatch.setattr( user_model.User.table.table, 'query_2', query_2) resp = user.get_user(current_user.email) assert resp.success assert resp.login == current_user.login assert spy.call_count == 2 def test_get_user_by_duplicated_email(monkeypatch, random_user): """Test getting a user by a duplicated email. An email can be used for more than one account. If the user tries to log in using an email, we return an error. """ current_user, password = random_user def query_2(**query): if query.get('email__eq') == current_user.email: return [current_user.message, current_user.message] return [] monkeypatch.setattr( user_model.User.table.table, 'query_2', query_2) resp = user.get_user(current_user.email) assert not resp.success assert resp.errors.get('email') def test_create_user(random_user): """Test creating a user.""" current_user, password = random_user assert current_user.success # The encrypted password should not be returned. assert not current_user.message.get('password') def test_update_user_password(monkeypatch, random_user): """Test updating a user passwor.""" current_user, password = random_user resp = user.update_user_password(current_user.id, password, clean=True) assert resp.success assert resp.login == current_user.login assert not resp.password def test_update_user_password_no_clean(monkeypatch, random_user): """Test updating a user passwor.""" fake = Faker() password = fake.password() current_user = user.create_user( fake.user_name(), password, fake.email(), clean=False) resp = user.update_user_password( current_user.id, 'a_new_password', clean=False) assert resp.success assert resp.login == current_user.login assert not passwords.check(password.encode('utf8'), resp.password) assert passwords.check(b'a_new_password', resp.password) def test_create_user_with_missing_info(): """Try creating twice the same user.""" fake = Faker() password = fake.password() email = fake.email() login = fake.user_name() assert not user.create_user(login, password, '').success resp = user.create_user(login, '', email) assert not resp.success assert resp.errors.get('password') resp = user.create_user('', password, email) assert not resp.success assert resp.errors.get('login') def test_login(monkeypatch): """Test login a user.""" current_user, password = random_user(clean=False) monkeypatch.setattr(user, 'get_user', MagicMock(return_value=current_user)) resp = user.login(current_user.login, password, 10982) assert resp.success assert resp.token def test_login_with_wrong_password(monkeypatch): """Test login a user with a wrong password.""" current_user, password = random_user(clean=False) error = response.create_error_response() monkeypatch.setattr(user, 'get_user', MagicMock(return_value=current_user)) monkeypatch.setattr(user, 'legacy_login', MagicMock(return_value=error)) resp = user.login(current_user.login, 'wrong password', 10982) assert not resp.success assert not resp.message.get('code') assert user.legacy_login.called def test_legacy_login_success_with_encrypted_password(monkeypatch): """Test a successful legacy logi.""" # Mock the password encryption and make sure it was called rsa_encrypt_spy = Mock() def encrypt(message, pubkey): rsa_encrypt_spy() return b'encrypted message' monkeypatch.setattr(rsa, 'encrypt', encrypt) # Mock the HTTP POST and make sure it was called http_post_spy = Mock() def post(url, params): http_post_spy() mock_response = requests.Response mock_response.status_code = 200 mock_response.content = ( b'{"id":"123","login":"PW",' b'"email":"patrick.walch@nuclearblast.de"}') return mock_response monkeypatch.setattr(requests, 'post', post) # perform the legacy login which should hit ALW with an HTTP POST resp = user.legacy_login('PW', 'orchard114', 10982) assert resp.success assert resp.token assert rsa_encrypt_spy.called assert http_post_spy.called def test_legacy_login_fail_with_encrypted_password(monkeypatch): """Test a successful legacy logi.""" # Mock the password encryption and make sure it was called rsa_encrypt_spy = Mock() def encrypt(message, pubkey): rsa_encrypt_spy() return b'encrypted message' monkeypatch.setattr(rsa, 'encrypt', encrypt) # Mock the HTTP POST and make sure it was called http_post_spy = Mock() def post(url, params): http_post_spy() mock_response = requests.Response mock_response.status_code = 403 return mock_response monkeypatch.setattr(requests, 'post', post) # perform the legacy login which should hit ALW with an HTTP POST resp = user.legacy_login('PW', 'incorrect password', 10982) assert not resp.success assert not resp.status == 200 assert rsa_encrypt_spy.called assert http_post_spy.called def test_legacy_login_updated_password(monkeypatch): """Test user logins in with updated remote passwor.""" current_user, password = random_user(clean=False) monkeypatch.setattr( user, 'update_user_password', MagicMock(return_value=current_user)) # Mock the password encryption and make sure it was called rsa_encrypt_spy = Mock() def encrypt(message, pubkey): rsa_encrypt_spy() return b'encrypted message' monkeypatch.setattr(rsa, 'encrypt', encrypt) # Mock the HTTP POST and make sure it was called http_post_spy = Mock() def post(url, params): http_post_spy() mock_response = requests.Response mock_response.status_code = 200 mock_response.content = ( b'{"id":"123","login":"current_user.login",' b'"email":"current_user.email"}') return mock_response monkeypatch.setattr(requests, 'post', post) # get a successful response from remote. should successfully get and # update local user record resp = user.legacy_login(current_user.login, 'new_remote_password', 10982) assert resp.success assert resp.status == 200 assert not resp.message.get('password') assert user.update_user_password.called assert rsa_encrypt_spy.called assert http_post_spy.called