diff --git a/anonstream/helpers/user.py b/anonstream/helpers/user.py index 41b1023..b4d8346 100644 --- a/anonstream/helpers/user.py +++ b/anonstream/helpers/user.py @@ -22,7 +22,9 @@ def generate_token_hash_and_tag(token): return token_hash, tag -def generate_user(timestamp, token, broadcaster, presence): +def generate_user( + timestamp, token, broadcaster, verified=False, presence=Presence.NOTWATCHING, +): colour = generate_colour( seed='name\0' + token, bg=CONFIG['CHAT_BACKGROUND_COLOUR'], @@ -34,7 +36,7 @@ def generate_user(timestamp, token, broadcaster, presence): 'token_hash': token_hash, 'tag': tag, 'broadcaster': broadcaster, - 'verified': broadcaster, + 'verified': verified or broadcaster, 'websockets': {}, 'name': None, 'color': colour_to_color(colour), diff --git a/anonstream/routes/core.py b/anonstream/routes/core.py index 69f0b15..fb9630a 100644 --- a/anonstream/routes/core.py +++ b/anonstream/routes/core.py @@ -14,6 +14,7 @@ from anonstream.user import watching, create_eyes, renew_eyes, EyesException, Ra from anonstream.routes.wrappers import with_user_from, auth_required, clean_cache_headers, generate_and_add_user from anonstream.helpers.captcha import check_captcha_digest, Answer from anonstream.utils.security import generate_csp +from anonstream.utils.user import identifying_string CAPTCHA_SIGNER = current_app.captcha_signer STATIC_DIRECTORY = current_app.root_path / 'static' @@ -71,9 +72,9 @@ async def stream(timestamp, user): raise StopSendingSegments( f'eyes {eyes_id} not allowed: {e!r}' ) from e - print(f'{uri}: {eyes_id}~{user["token"]}') + print(f'{uri}: \033[37m{eyes_id}\033[0m~{identifying_string(user)}') watching(user) - generator = segments(segment_read_hook, token=user['token']) + generator = segments(segment_read_hook, token=f'\033[35m{user["token"]}\033[0m') response = await make_response(generator) response.headers['Content-Type'] = 'video/mp4' response.timeout = None @@ -112,7 +113,7 @@ async def access(timestamp, user_or_token): failure_id = add_failure('Captcha has expired') case Answer.OK: failure_id = None - user = generate_and_add_user(timestamp, token) + user = generate_and_add_user(timestamp, token, verified=True) if failure_id is not None: url = url_for('home', token=token, failure=failure_id) raise abort(redirect(url, 303)) diff --git a/anonstream/routes/wrappers.py b/anonstream/routes/wrappers.py index 339489b..3bcc606 100644 --- a/anonstream/routes/wrappers.py +++ b/anonstream/routes/wrappers.py @@ -72,13 +72,15 @@ def auth_required(f): return response return wrapper -def generate_and_add_user(timestamp, token=None, broadcaster=False): +def generate_and_add_user( + timestamp, token=None, broadcaster=False, verified=False, +): token = token or generate_token() user = generate_user( timestamp=timestamp, token=token, broadcaster=broadcaster, - presence=Presence.NOTWATCHING, + verified=verified, ) USERS_BY_TOKEN[token] = user USERS_UPDATE_BUFFER.add(token) diff --git a/anonstream/segments.py b/anonstream/segments.py index 84c5570..476e4c0 100644 --- a/anonstream/segments.py +++ b/anonstream/segments.py @@ -91,7 +91,7 @@ async def get_segment_uris(token): except Offline as e: reason, *_ = e.args print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'stream went offline before we could find any segments ({reason})' ) return @@ -109,7 +109,7 @@ async def get_segment_uris(token): except Offline as e: reason, *_ = e.args print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'stream went offline while looking for the ' f'segment following {segment.uri!r} ({reason})' ) @@ -120,7 +120,7 @@ async def get_segment_uris(token): break elif time.monotonic() - t0 >= CONFIG['SEGMENT_SEARCH_TIMEOUT']: print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'timed out looking for the segment following ' f'{segment.uri!r} ' f'(timeout={CONFIG["SEGMENT_SEARCH_TIMEOUT"]}s)' @@ -138,15 +138,15 @@ def path_for(uri): return path async def segments(segment_read_hook=lambda uri: None, token=None): - print(f'[debug @ {time.time():.3f}: {token=}] entering segment generator') + print(f'[debug @ {time.time():.3f}: token={token}] entering segment generator') async for uri in get_segment_uris(token): - #print(f'[debug @ {time.time():.3f}: {token=}] {uri=}') + #print(f'[debug @ {time.time():.3f}: token={token}] {uri=}') try: path = path_for(uri) except UnsafePath as e: unsafe_path, *_ = e.args print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'segment {uri=} has {unsafe_path=}' ) break @@ -156,7 +156,7 @@ async def segments(segment_read_hook=lambda uri: None, token=None): except StopSendingSegments as e: reason, *_ = e.args print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'told to stop sending segments: {reason}' ) break @@ -166,14 +166,14 @@ async def segments(segment_read_hook=lambda uri: None, token=None): yield chunk except FileNotFoundError: print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'segment {uri=} at {path=} unexpectedly does not exist' ) break except OSError as e: print( - f'[debug @ {time.time():.3f}: {token=}] ' + f'[debug @ {time.time():.3f}: token={token}] ' f'segment {uri=} at {path=} cannot be read: {e}' ) break - print(f'[debug @ {time.time():.3f}: {token=}] exiting segment generator') + print(f'[debug @ {time.time():.3f}: token={token}] exiting segment generator') diff --git a/anonstream/user.py b/anonstream/user.py index ccdb360..112d8d3 100644 --- a/anonstream/user.py +++ b/anonstream/user.py @@ -174,7 +174,7 @@ def verify(user, digest, answer): @with_timestamp() def deverify(timestamp, user): - if user['verified']: + if user['verified'] and not user['broadcaster']: n_user_messages = 0 for message in reversed(MESSAGES): message_sent_ago = timestamp - message['timestamp'] diff --git a/anonstream/utils/user.py b/anonstream/utils/user.py index ed2c12e..463db6a 100644 --- a/anonstream/utils/user.py +++ b/anonstream/utils/user.py @@ -50,3 +50,13 @@ def get_user_for_websocket(user): **{key: user[key] for key in USER_WEBSOCKET_ATTRS}, 'watching': trilean(user['presence']), } + +def identifying_string(user, ansi=True): + tag = user['tag'] + token_hash = f'{user["token_hash"][:4]}..' + token = user['token'] + if ansi: + tag = f'\033[36m{tag}\033[0m' + token_hash = f'\033[32m{token_hash}\033[0m' + token = f'\033[35m{token}\033[0m' + return '/'.join((tag, token_hash, token)) diff --git a/anonstream/websocket.py b/anonstream/websocket.py index 0c21382..f358235 100644 --- a/anonstream/websocket.py +++ b/anonstream/websocket.py @@ -12,6 +12,7 @@ from anonstream.chat import get_all_messages_for_websocket, add_chat_message, Re from anonstream.user import get_all_users_for_websocket, see, reading, verify, deverify, BadCaptcha, try_change_appearance from anonstream.wrappers import with_timestamp from anonstream.utils.chat import generate_nonce +from anonstream.utils.user import identifying_string from anonstream.utils.websocket import parse_websocket_data, Malformed, WS CONFIG = current_app.config @@ -74,7 +75,7 @@ async def websocket_inbound(queue, user): @with_timestamp() def handle_inbound_pong(timestamp, queue, user): - print(f'[pong] {user["token"]}') + print(f'[pong] {identifying_string(user)}') reading(user, timestamp=timestamp) user['websockets'][queue] = timestamp return None