Secure media uploads expire

We have a client having issues with secure media uploads.
This client is running a docker based Discourse (official install) with AWS S3 and secure media enabled.

The forum has a number of mp3 and m4a sound files.

Discourse automatically embeds a nice player like this:

image

Problem: the sound files do not work reliably. Sometimes they do not play.

I cannot reproduce this 100% reliable, I think because of caching, but it seems that the download is postponed until the play button is pressed. That sounds logical and good.

But it doesn’t play nice with secure media uploads - if you leave a page open for a while and press the play button after a minute or so, the sound file does not (always) play. At that point, AWS returns a 403 Expired error. It looks like the request is not signed at the moment the file is requested, but earlier. The error message clearly states that the request expired in the past.

I suspect this has to do with the delay, but I am not 100% sure. Fact is that this is happening to sound files only (i.e. not to embedded images which are always downloaded immediately).

Yes, server time is correct.

I can repro on a fresh install running latest beta. Just put two sound files in a topic and mess around a bit.

2 Likes

That may be because of how browsers work with audio and video tags and the default value of preload. Are the files specially long? AFAIK browsers will download using byte ranges on demand.

4 Likes

No, they’re not long, the files are just a few ( < 5) megabytes and they’re not being downloaded in ranges.

What do you mean by 'the default value of preload ?

If you have a <audio> or <video> tag, setting an attribute of preload=auto on it will hint the browser to download it all on page load, so you wouldn’t have this problem with the signed s3 url expiring.

As with those things always go, sites started to abuse this attribute and it isn’t always blindly followed anymore, but is a hint the browser will consider.

6 Likes

There is no explicit <audio> tag, it is generated automatically by Discourse when the audio file is being inserted. Without a preload attribute.

The part I don’t get: if the /secure-media-uploads route is generating the signed URL, why does it matter how much time there is between the page load and the route getting hit? After all, it is generating the signed route and then immediately redirecting to that. But somehow, it does seem to matter. It seems like something is being cached or something?

There is in the generated HTML from the post markdown, and that is what I’m talking about. I’d say it makes sense to add that attribute when the setting is enabled.

I believe the whole of point of the feature is exactly that. Have URLs that can’t be shared elsewhere for the uploads, and the only way to have that is using URLs that expire.

5 Likes

Yes, I understand that. And the expire timer starts counting at the moment the /secure-media-uploads route is called, and not when the page is being loaded.

Still, it seems to matter if the page was loaded long before the route is hit. And then it breaks, somehow. I just don’t get why this is happening.

This has now been fixed here https://github.com/discourse/discourse/commit/7ff58f17877cd5b5ce6e96def47aa7719e843977 @RGJ. The problem was happening because browsers send an initial request to audio + video files to get metadata for the file e.g. duration. However because of the secure presigned URL, this initial request started the 15 second expiry countdown, so when users went to play audio + video after that time period we got the 403 error from AWS.

We now disable preloading on video + audio when secure media is enabled. Existing posts with audio + video will need to have their HTML rebuilt to see the change.

13 Likes