As opposed to just the broadcaster token. This makes the broadcaster
username/password login mandatory, which previously was only mandatory
in the `auth_required` wrapper, but not elsewhere (so for example
leaving comments as the broadcaster was possible with the token only). A
less safe alternative to this would be to compare tokens in `check_auth`
once the Authorization header didn't match.
Also implements stack/queue behaviour where if the eyes limit would be
exceeded, either the new eyes cause the oldest eyes to be deleted OR
the new eyes aren't created at all. The default is the first option.
This commit adds the concept of eyes. One "eyes" is one instance of a
response to GET /stream.mp4. Currently the number of eyes clients can
have is unbounded, but this is a DoS vector.
Client and server both close the connection if they don't hear from the
other party after a timeout period. This is a failsafe and should
improve reliability.
Might not be necessary, but if it is then it prevents a sitation where a
websocket is still open but we've forgotten about it, so we will never
broadcast any new messages to it and the client will be practically frozen in
time until they disconnect and open a new websocket.
Also update the user's last_seen when the websocket is closed. This prevents a
user with js enabled who's actually idle being considered absent and being
rotated when their websocket accidentally closes for a few seconds.
The nojs button appears when the stream is online and the user is not watching.
The js button appears when the stream is online and the media element either
(1) is not using the network or (2) fires an error event.
Matches the behaviour of the js chat. Makes it so if you submit an empty
message but with a correct captcha, you won't be deverified and given another
captcha until you successfully send a message (and exceed the flood threshold).
Previously you could fill in the captcha with no message and be given back a
new captcha, which doesn't make that much sense.
This adds a field 'watching' in `user_for_websocket` that's True iff WATCHING,
False iff NOTWATCHING, and None otherwise (since clients don't need to know if
a user is tentative or absent). When the value of this field changes for any
user, they get added to the update buffer (like with any other change).
Removed race condition in `t_sunset_users`: `broadcast_users_update` was being
called *after* a user was removed from memory (and for each user being removed,
which was redundant). In that scenario if there's a user in the update buffer
and `t_sunset_users` wins the race between it and `t_broadcast_users_update`,
then when `t_sunset_users` calls `broadcast_users_update` a KeyError would be
raised since the user's already been removed.
Fixed unintended behaviour of `t_sunset_users`: it was removing users based on
the result of `is_visible`, so users who were actually tenative (as opposed to
absent) were being removed.
By default the buffer is exhausted every 4 seconds. This should defend against
a potential DoS against clients with JavaScript enabled. Before this, any
request with no token would generate a new user and immediately broadcast the
new user to all the websockets. It's best to lock down as much as possible the
number of places a client can cause the server to broadcasts to all the
websockets.
Incoming requests are handled in anonstream/routes/. Route handlers
mainly depend on files in anonstream/, which in turn depend on files in
anonstream/helpers/ and anonstream/utils/. Utils are pure functions and
helpers are almost pure functions; they don't mutate state but they
do depend on the global app config.