Skip to content

Commit 27ce595

Browse files
committed
Fix & test cross-posting of uploads
Add tests for cross-room file references. We were correctly handling not allowing cross-room references of post attachments, but cross-room references of the room image was allowed (now fixed).
1 parent 03f8dad commit 27ce595

File tree

4 files changed

+47
-7
lines changed

4 files changed

+47
-7
lines changed

sogs/model/exc.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def __init__(self, token):
1818

1919

2020
class NoSuchFile(NotFound):
21-
"""Thrown when trying to construct a File from a token that doesn't exist"""
21+
"""Thrown when trying to construct a File from an id that doesn't exist"""
2222

2323
def __init__(self, id):
2424
self.id = id

sogs/model/room.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,9 @@ def image(self, file: Union[File, int]):
269269
if not isinstance(file, File):
270270
file = File(id=file)
271271

272+
if file.room_id != self.id:
273+
raise NoSuchFile(file.room_id)
274+
272275
file.set_expiry(forever=True)
273276

274277
if self.image:

sogs/routes/rooms.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .. import config, db, http
2-
from ..model import room as mroom
2+
from ..model import room as mroom, exc
33
from ..web import app
44
from . import auth
55

@@ -198,7 +198,7 @@ def update_room(room):
198198
update the room's default read, access, write, and upload permissions for ordinary users (i.e.
199199
users who do not have any other user-specific permission applied). See the description of
200200
Access permissions in the (room information)[#get-roomroom] endpoint for details.
201-
- `image` — The file id of an image that was uploaded to use as the room icon.
201+
- `image` — The file id of an image that was uploaded in this room to use as the room icon.
202202
203203
# Return value
204204
@@ -207,6 +207,9 @@ def update_room(room):
207207
# Error status codes
208208
209209
- 403 Forbidden — if the invoking user does not have administrator access to the room.
210+
211+
- 406 Not Acceptable — if the given data is not acceptable. Currently this response occurs if a
212+
given `image` is invalid (i.e. does not exist, or is not uploaded to this room).
210213
"""
211214

212215
req = request.json
@@ -240,7 +243,11 @@ def update_room(room):
240243
if not isinstance(img, int):
241244
app.logger.warning(f"Room update: invalid image: {type(id)} is not an integer")
242245
abort(http.BAD_REQUEST)
243-
room.image = img
246+
try:
247+
room.image = img
248+
except exc.NoSuchFile as e:
249+
app.logger.warning(f"Room image update invalid: {e}")
250+
abort(http.NOT_ACCEPTABLE)
244251
did = True
245252

246253
for val in (read, accessible, write, upload):

tests/test_room_routes.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,7 +1065,7 @@ def _make_file_upload(filename):
10651065
return random(1024), {"Content-Disposition": ('attachment', {'filename': filename})}
10661066

10671067

1068-
def test_owned_files(client, room, user, admin):
1068+
def test_owned_files(client, room, room2, user, admin):
10691069
# - upload a file via new endpoints
10701070
filedata, headers = _make_file_upload('fug-1.jpeg')
10711071
r = sogs_post_raw(client, f'/room/{room.token}/file', filedata, user, extra_headers=headers)
@@ -1125,8 +1125,14 @@ def test_owned_files(client, room, user, admin):
11251125
filedata, headers = _make_file_upload('another.png')
11261126
r = sogs_post_raw(client, f'/room/{room.token}/file', filedata, user, extra_headers=headers)
11271127
assert r.status_code == 201
1128+
f3 = File(id=r.json['id'])
1129+
assert f3.expiry == from_now.hours(1)
11281130
d, s = (utils.encode_base64(x) for x in (b"more post data", pad64("fsdf")))
1129-
post_info = {'data': d, 'signature': s, 'files': [f1.id, r.json['id']]}
1131+
post_info = {'data': d, 'signature': s, 'files': [f1.id, f3.id]}
1132+
r = sogs_put(client, f'/room/{room.token}/message/{post_id}', post_info, user)
1133+
assert r.status_code == 200
1134+
f3 = File(id=f3.id)
1135+
assert f3.expiry == from_now.days(15)
11301136

11311137
# - make sure the first post associated message hasn't changed (i.e. no stealing owned uploads)
11321138
f1a = File(id=f1.id)
@@ -1148,6 +1154,8 @@ def test_owned_files(client, room, user, admin):
11481154
# - make a post referencing the room image ID
11491155
d, s = (utils.encode_base64(x) for x in (b"post xyz", pad64("z")))
11501156
post_info = {'data': d, 'signature': s, 'files': [room_img]}
1157+
r = sogs_put(client, f'/room/{room.token}/message/{post_id}', post_info, user)
1158+
assert r.status_code == 200
11511159

11521160
# - verify that the pinned image expiry and message are still both NULL
11531161
f_room = File(id=f_room.id)
@@ -1165,14 +1173,36 @@ def test_owned_files(client, room, user, admin):
11651173

11661174
from sogs.cleanup import cleanup
11671175

1168-
assert cleanup() == (2, 0, 0, 0, 0)
1176+
# Cleanup should remove 3 attachments: the two originals plus the one we added via an edit:
1177+
assert cleanup() == (3, 0, 0, 0, 0)
11691178

11701179
with pytest.raises(sogs.model.exc.NoSuchFile):
11711180
f1 = File(id=f1.id)
11721181
with pytest.raises(sogs.model.exc.NoSuchFile):
11731182
f2 = File(id=f2.id)
11741183

11751184

1185+
def test_no_file_crosspost(client, room, room2, user, global_admin):
1186+
# Disallow cross-room references (i.e. a post attaching a file uploaded to another room)
1187+
filedata, headers = _make_file_upload('room2-file.jpg')
1188+
r = sogs_post_raw(client, f'/room/{room2.token}/file', filedata, user, extra_headers=headers)
1189+
assert r.status_code == 201
1190+
f = File(id=r.json['id'])
1191+
d, s = (utils.encode_base64(x) for x in (b"room1 post", pad64("sig123")))
1192+
post_info = {'data': d, 'signature': s, 'files': [f.id]}
1193+
r = sogs_post(client, f'/room/{room.token}/message', post_info, user)
1194+
assert r.status_code == 201
1195+
1196+
f = File(id=f.id)
1197+
# The file isn't for a post in room 1, so shouldn't have been associated:
1198+
assert f.post_id is None
1199+
assert f.expiry == from_now.hours(1)
1200+
1201+
# Disallow setting the room image to some foreign room's upload
1202+
r = sogs_put(client, f'/room/{room.token}', {'image': f.id}, global_admin)
1203+
assert r.status_code == 406
1204+
1205+
11761206
def _make_dummy_post(room, user):
11771207
msg = room.add_post(user, b'data', b'a' * 64)
11781208
return msg.get('id')

0 commit comments

Comments
 (0)