diff options
Diffstat (limited to 'tests/users')
| -rw-r--r-- | tests/users/models/test_identity.py | 178 | ||||
| -rw-r--r-- | tests/users/views/test_activitypub.py | 31 | ||||
| -rw-r--r-- | tests/users/views/test_auth.py | 59 | 
3 files changed, 268 insertions, 0 deletions
| diff --git a/tests/users/models/test_identity.py b/tests/users/models/test_identity.py new file mode 100644 index 0000000..13c08f0 --- /dev/null +++ b/tests/users/models/test_identity.py @@ -0,0 +1,178 @@ +import pytest +from asgiref.sync import async_to_sync + +from core.models import Config +from users.models import Domain, Identity, User +from users.views.identity import CreateIdentity + + +@pytest.mark.django_db +def test_create_identity_form(config_system, client): +    """ """ +    # Make a user +    user = User.objects.create(email="test@example.com") +    admin = User.objects.create(email="admin@example.com", admin=True) +    # Make a domain +    domain = Domain.objects.create(domain="example.com", local=True) +    domain.users.add(user) +    domain.users.add(admin) + +    # Test identity_min_length +    data = { +        "username": "a", +        "domain": domain.domain, +        "name": "The User", +    } + +    form = CreateIdentity.form_class(user=user, data=data) +    assert not form.is_valid() +    assert "username" in form.errors +    assert "value has at least" in form.errors["username"][0] + +    form = CreateIdentity.form_class(user=admin, data=data) +    assert form.errors == {} + +    # Test restricted_usernames +    data = { +        "username": "@root", +        "domain": domain.domain, +        "name": "The User", +    } + +    form = CreateIdentity.form_class(user=user, data=data) +    assert not form.is_valid() +    assert "username" in form.errors +    assert "restricted to administrators" in form.errors["username"][0] + +    form = CreateIdentity.form_class(user=admin, data=data) +    assert form.errors == {} + +    # Test valid chars +    data = { +        "username": "@someval!!!!", +        "domain": domain.domain, +        "name": "The User", +    } + +    for u in (user, admin): +        form = CreateIdentity.form_class(user=u, data=data) +        assert not form.is_valid() +        assert "username" in form.errors +        assert form.errors["username"][0].startswith("Only the letters") + + +@pytest.mark.django_db +def test_identity_max_per_user(config_system, client): +    """ +    Ensures that the identity limit is functioning +    """ +    # Make a user +    user = User.objects.create(email="test@example.com") +    # Make a domain +    domain = Domain.objects.create(domain="example.com", local=True) +    domain.users.add(user) +    # Make an identity for them +    for i in range(Config.system.identity_max_per_user): +        identity = Identity.objects.create( +            actor_uri=f"https://example.com/@test{i}@example.com/actor/", +            username=f"test{i}", +            domain=domain, +            name=f"Test User{i}", +            local=True, +        ) +        identity.users.add(user) + +    data = { +        "username": "toomany", +        "domain": domain.domain, +        "name": "Too Many", +    } +    form = CreateIdentity.form_class(user=user, data=data) +    assert form.errors["__all__"][0].startswith("You are not allowed more than") + +    user.admin = True +    form = CreateIdentity.form_class(user=user, data=data) +    assert form.is_valid() + + +@pytest.mark.django_db +def test_fetch_actor(httpx_mock, config_system): +    """ +    Ensures that making identities via actor fetching works +    """ +    # Make a shell remote identity +    identity = Identity.objects.create( +        actor_uri="https://example.com/test-actor/", +        local=False, +    ) + +    # Trigger actor fetch +    httpx_mock.add_response( +        url="https://example.com/.well-known/webfinger?resource=acct:test@example.com", +        json={ +            "subject": "acct:test@example.com", +            "aliases": [ +                "https://example.com/test-actor/", +            ], +            "links": [ +                { +                    "rel": "http://webfinger.net/rel/profile-page", +                    "type": "text/html", +                    "href": "https://example.com/test-actor/", +                }, +                { +                    "rel": "self", +                    "type": "application/activity+json", +                    "href": "https://example.com/test-actor/", +                }, +            ], +        }, +    ) +    httpx_mock.add_response( +        url="https://example.com/test-actor/", +        json={ +            "@context": [ +                "https://www.w3.org/ns/activitystreams", +                "https://w3id.org/security/v1", +            ], +            "id": "https://example.com/test-actor/", +            "type": "Person", +            "inbox": "https://example.com/test-actor/inbox/", +            "publicKey": { +                "id": "https://example.com/test-actor/#main-key", +                "owner": "https://example.com/test-actor/", +                "publicKeyPem": "-----BEGIN PUBLIC KEY-----\nits-a-faaaake\n-----END PUBLIC KEY-----\n", +            }, +            "followers": "https://example.com/test-actor/followers/", +            "following": "https://example.com/test-actor/following/", +            "icon": { +                "type": "Image", +                "mediaType": "image/jpeg", +                "url": "https://example.com/icon.jpg", +            }, +            "image": { +                "type": "Image", +                "mediaType": "image/jpeg", +                "url": "https://example.com/image.jpg", +            }, +            "as:manuallyApprovesFollowers": False, +            "name": "Test User", +            "preferredUsername": "test", +            "published": "2022-11-02T00:00:00Z", +            "summary": "<p>A test user</p>", +            "url": "https://example.com/test-actor/view/", +        }, +    ) +    async_to_sync(identity.fetch_actor)() + +    # Verify the data arrived +    identity = Identity.objects.get(pk=identity.pk) +    assert identity.name == "Test User" +    assert identity.username == "test" +    assert identity.domain_id == "example.com" +    assert identity.profile_uri == "https://example.com/test-actor/view/" +    assert identity.inbox_uri == "https://example.com/test-actor/inbox/" +    assert identity.icon_uri == "https://example.com/icon.jpg" +    assert identity.image_uri == "https://example.com/image.jpg" +    assert identity.summary == "<p>A test user</p>" +    assert "ts-a-faaaake" in identity.public_key diff --git a/tests/users/views/test_activitypub.py b/tests/users/views/test_activitypub.py new file mode 100644 index 0000000..72ab8c3 --- /dev/null +++ b/tests/users/views/test_activitypub.py @@ -0,0 +1,31 @@ +import pytest + +from users.models import Domain, Identity, User + + +@pytest.mark.django_db +def test_webfinger_actor(client): +    """ +    Ensures the webfinger and actor URLs are working properly +    """ +    # Make a user +    user = User.objects.create(email="test@example.com") +    # Make a domain +    domain = Domain.objects.create(domain="example.com", local=True) +    domain.users.add(user) +    # Make an identity for them +    identity = Identity.objects.create( +        actor_uri="https://example.com/@test@example.com/", +        username="test", +        domain=domain, +        name="Test User", +        local=True, +    ) +    identity.generate_keypair() +    # Fetch their webfinger +    data = client.get("/.well-known/webfinger?resource=acct:test@example.com").json() +    assert data["subject"] == "acct:test@example.com" +    assert data["aliases"][0] == "https://example.com/@test/" +    # Fetch their actor +    data = client.get("/@test@example.com/", HTTP_ACCEPT="application/ld+json").json() +    assert data["id"] == "https://example.com/@test@example.com/" diff --git a/tests/users/views/test_auth.py b/tests/users/views/test_auth.py new file mode 100644 index 0000000..22e1fb6 --- /dev/null +++ b/tests/users/views/test_auth.py @@ -0,0 +1,59 @@ +import mock +import pytest + +from core.models import Config +from users.models import User + + +@pytest.fixture +def config_system(): +    # TODO: Good enough for now, but a better Config mocking system is needed +    result = Config.load_system() +    with mock.patch("core.models.Config.load_system", return_value=result): +        yield result + + +@pytest.mark.django_db +def test_signup_disabled(client, config_system): +    # Signup disabled and no signup text +    config_system.signup_allowed = False +    resp = client.get("/auth/signup/") +    assert resp.status_code == 200 +    content = str(resp.content) +    assert "Not accepting new users at this time" in content +    assert "<button>Create</button>" not in content + +    # Signup disabled with signup text configured +    config_system.signup_text = "Go away!!!!!!" +    resp = client.get("/auth/signup/") +    assert resp.status_code == 200 +    content = str(resp.content) +    assert "Go away!!!!!!" in content + +    # Ensure direct POST doesn't side step guard +    resp = client.post( +        "/auth/signup/", data={"email": "test_signup_disabled@example.org"} +    ) +    assert resp.status_code == 200 +    assert not User.objects.filter(email="test_signup_disabled@example.org").exists() + +    # Signup enabled +    config_system.signup_allowed = True +    resp = client.get("/auth/signup/") +    assert resp.status_code == 200 +    content = str(resp.content) +    assert "Not accepting new users at this time" not in content +    assert "<button>Create</button>" in content + + +@pytest.mark.django_db +def test_signup_invite_only(client, config_system): +    config_system.signup_allowed = True +    config_system.signup_invite_only = True + +    resp = client.get("/auth/signup/") +    assert resp.status_code == 200 +    content = str(resp.content) +    assert 'name="invite_code"' in content + +    # TODO: Actually test this | 
