aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_group_description.py
blob: b41a7db1340832b870785e71136c795f8183b87a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
"""
Editing a group's description.

A description could only be set when the group was created, so every group made
before anyone thought to write one stayed blank for good. What is deliberately
*not* editable is as much the point: name, visibility and join policy are the
terms members joined on.
"""

import base64
import hashlib

import pytest


def _auth_key(password: str, username: str) -> str:
    salt = hashlib.sha256(f"meshbay:auth:v1:{username}".encode()).digest()
    return base64.b64encode(
        hashlib.pbkdf2_hmac("sha512", password.encode(), salt, 600_000, 32)).decode()


async def _user(client, username, password="a-long-enough-passphrase"):
    await client.post("/v1/users/register", json={
        "username": username, "email": f"{username}@example.com",
        "auth_key": _auth_key(password, username)})
    r = await client.post("/v1/users/login", json={
        "username": username, "auth_key": _auth_key(password, username)})
    return {"Authorization": f"Bearer {r.json()['access_token']}"}


async def _group(client, headers, name="described", **kw):
    r = await client.post("/v1/groups", json={"name": name, **kw}, headers=headers)
    return r.json()["group_id"]


@pytest.mark.asyncio
async def test_the_owner_can_write_a_description(client):
    owner = await _user(client, "writer_test")
    gid = await _group(client, owner)

    r = await client.patch(f"/v1/groups/{gid}",
                           json={"description": "host grenoble"}, headers=owner)
    assert r.status_code == 200, r.text

    mine = await client.get("/v1/groups/mine", headers=owner)
    group = next(g for g in mine.json()["groups"] if g["id"] == gid)
    assert group["description"] == "host grenoble"


@pytest.mark.asyncio
async def test_a_member_cannot(client):
    owner = await _user(client, "owner2_test")
    member = await _user(client, "member2_test")
    gid = await _group(client, owner, name="not-yours")
    await client.post(f"/v1/groups/{gid}/members/member2_test", json={}, headers=owner)

    r = await client.patch(f"/v1/groups/{gid}",
                           json={"description": "mine now"}, headers=member)
    assert r.status_code == 403


@pytest.mark.asyncio
async def test_an_empty_description_clears_it(client):
    owner = await _user(client, "clearer_test")
    gid = await _group(client, owner, name="clearme", description="temporary")

    r = await client.patch(f"/v1/groups/{gid}", json={"description": "   "},
                           headers=owner)
    assert r.status_code == 200
    assert r.json()["description"] == ""


@pytest.mark.asyncio
async def test_the_terms_members_joined_on_are_not_editable(client):
    """
    A private group that could quietly become public is not the group its
    members agreed to be in. Changing that needs a decision about who gets told,
    so the endpoint ignores it rather than half-implementing it.
    """
    owner = await _user(client, "sneaky_test")
    gid = await _group(client, owner, name="private-please", visibility="private")

    await client.patch(f"/v1/groups/{gid}",
                       json={"description": "hi", "visibility": "public",
                             "join_policy": "open", "name": "renamed"},
                       headers=owner)

    mine = await client.get("/v1/groups/mine", headers=owner)
    group = next(g for g in mine.json()["groups"] if g["id"] == gid)
    assert group["visibility"] == "private"
    assert group["join_policy"] == "invite"
    assert group["name"] == "private-please"


@pytest.mark.asyncio
async def test_a_long_description_is_truncated_not_refused(client):
    owner = await _user(client, "verbose_test")
    gid = await _group(client, owner, name="long")

    r = await client.patch(f"/v1/groups/{gid}", json={"description": "x" * 900},
                           headers=owner)
    assert r.status_code == 200
    assert len(r.json()["description"]) == 512