Merge branch 'dev'
このコミットが含まれているのは:
コミット
c6117a6f36
|
@ -22,7 +22,9 @@ def generate_token_hash_and_tag(token):
|
||||||
|
|
||||||
return token_hash, tag
|
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(
|
colour = generate_colour(
|
||||||
seed='name\0' + token,
|
seed='name\0' + token,
|
||||||
bg=CONFIG['CHAT_BACKGROUND_COLOUR'],
|
bg=CONFIG['CHAT_BACKGROUND_COLOUR'],
|
||||||
|
@ -34,7 +36,7 @@ def generate_user(timestamp, token, broadcaster, presence):
|
||||||
'token_hash': token_hash,
|
'token_hash': token_hash,
|
||||||
'tag': tag,
|
'tag': tag,
|
||||||
'broadcaster': broadcaster,
|
'broadcaster': broadcaster,
|
||||||
'verified': broadcaster,
|
'verified': verified or broadcaster,
|
||||||
'websockets': {},
|
'websockets': {},
|
||||||
'name': None,
|
'name': None,
|
||||||
'color': colour_to_color(colour),
|
'color': colour_to_color(colour),
|
||||||
|
|
|
@ -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.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.helpers.captcha import check_captcha_digest, Answer
|
||||||
from anonstream.utils.security import generate_csp
|
from anonstream.utils.security import generate_csp
|
||||||
|
from anonstream.utils.user import identifying_string
|
||||||
|
|
||||||
CAPTCHA_SIGNER = current_app.captcha_signer
|
CAPTCHA_SIGNER = current_app.captcha_signer
|
||||||
STATIC_DIRECTORY = current_app.root_path / 'static'
|
STATIC_DIRECTORY = current_app.root_path / 'static'
|
||||||
|
@ -71,9 +72,9 @@ async def stream(timestamp, user):
|
||||||
raise StopSendingSegments(
|
raise StopSendingSegments(
|
||||||
f'eyes {eyes_id} not allowed: {e!r}'
|
f'eyes {eyes_id} not allowed: {e!r}'
|
||||||
) from e
|
) from e
|
||||||
print(f'{uri}: {eyes_id}~{user["token"]}')
|
print(f'{uri}: \033[37m{eyes_id}\033[0m~{identifying_string(user)}')
|
||||||
watching(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 = await make_response(generator)
|
||||||
response.headers['Content-Type'] = 'video/mp4'
|
response.headers['Content-Type'] = 'video/mp4'
|
||||||
response.timeout = None
|
response.timeout = None
|
||||||
|
@ -112,7 +113,7 @@ async def access(timestamp, user_or_token):
|
||||||
failure_id = add_failure('Captcha has expired')
|
failure_id = add_failure('Captcha has expired')
|
||||||
case Answer.OK:
|
case Answer.OK:
|
||||||
failure_id = None
|
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:
|
if failure_id is not None:
|
||||||
url = url_for('home', token=token, failure=failure_id)
|
url = url_for('home', token=token, failure=failure_id)
|
||||||
raise abort(redirect(url, 303))
|
raise abort(redirect(url, 303))
|
||||||
|
|
|
@ -72,13 +72,15 @@ def auth_required(f):
|
||||||
return response
|
return response
|
||||||
return wrapper
|
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()
|
token = token or generate_token()
|
||||||
user = generate_user(
|
user = generate_user(
|
||||||
timestamp=timestamp,
|
timestamp=timestamp,
|
||||||
token=token,
|
token=token,
|
||||||
broadcaster=broadcaster,
|
broadcaster=broadcaster,
|
||||||
presence=Presence.NOTWATCHING,
|
verified=verified,
|
||||||
)
|
)
|
||||||
USERS_BY_TOKEN[token] = user
|
USERS_BY_TOKEN[token] = user
|
||||||
USERS_UPDATE_BUFFER.add(token)
|
USERS_UPDATE_BUFFER.add(token)
|
||||||
|
|
|
@ -91,7 +91,7 @@ async def get_segment_uris(token):
|
||||||
except Offline as e:
|
except Offline as e:
|
||||||
reason, *_ = e.args
|
reason, *_ = e.args
|
||||||
print(
|
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})'
|
f'stream went offline before we could find any segments ({reason})'
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
@ -109,7 +109,7 @@ async def get_segment_uris(token):
|
||||||
except Offline as e:
|
except Offline as e:
|
||||||
reason, *_ = e.args
|
reason, *_ = e.args
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'stream went offline while looking for the '
|
f'stream went offline while looking for the '
|
||||||
f'segment following {segment.uri!r} ({reason})'
|
f'segment following {segment.uri!r} ({reason})'
|
||||||
)
|
)
|
||||||
|
@ -120,7 +120,7 @@ async def get_segment_uris(token):
|
||||||
break
|
break
|
||||||
elif time.monotonic() - t0 >= CONFIG['SEGMENT_SEARCH_TIMEOUT']:
|
elif time.monotonic() - t0 >= CONFIG['SEGMENT_SEARCH_TIMEOUT']:
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'timed out looking for the segment following '
|
f'timed out looking for the segment following '
|
||||||
f'{segment.uri!r} '
|
f'{segment.uri!r} '
|
||||||
f'(timeout={CONFIG["SEGMENT_SEARCH_TIMEOUT"]}s)'
|
f'(timeout={CONFIG["SEGMENT_SEARCH_TIMEOUT"]}s)'
|
||||||
|
@ -138,15 +138,15 @@ def path_for(uri):
|
||||||
return path
|
return path
|
||||||
|
|
||||||
async def segments(segment_read_hook=lambda uri: None, token=None):
|
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):
|
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:
|
try:
|
||||||
path = path_for(uri)
|
path = path_for(uri)
|
||||||
except UnsafePath as e:
|
except UnsafePath as e:
|
||||||
unsafe_path, *_ = e.args
|
unsafe_path, *_ = e.args
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'segment {uri=} has {unsafe_path=}'
|
f'segment {uri=} has {unsafe_path=}'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
@ -156,7 +156,7 @@ async def segments(segment_read_hook=lambda uri: None, token=None):
|
||||||
except StopSendingSegments as e:
|
except StopSendingSegments as e:
|
||||||
reason, *_ = e.args
|
reason, *_ = e.args
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'told to stop sending segments: {reason}'
|
f'told to stop sending segments: {reason}'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
@ -166,14 +166,14 @@ async def segments(segment_read_hook=lambda uri: None, token=None):
|
||||||
yield chunk
|
yield chunk
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'segment {uri=} at {path=} unexpectedly does not exist'
|
f'segment {uri=} at {path=} unexpectedly does not exist'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print(
|
print(
|
||||||
f'[debug @ {time.time():.3f}: {token=}] '
|
f'[debug @ {time.time():.3f}: token={token}] '
|
||||||
f'segment {uri=} at {path=} cannot be read: {e}'
|
f'segment {uri=} at {path=} cannot be read: {e}'
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
print(f'[debug @ {time.time():.3f}: {token=}] exiting segment generator')
|
print(f'[debug @ {time.time():.3f}: token={token}] exiting segment generator')
|
||||||
|
|
|
@ -174,7 +174,7 @@ def verify(user, digest, answer):
|
||||||
|
|
||||||
@with_timestamp()
|
@with_timestamp()
|
||||||
def deverify(timestamp, user):
|
def deverify(timestamp, user):
|
||||||
if user['verified']:
|
if user['verified'] and not user['broadcaster']:
|
||||||
n_user_messages = 0
|
n_user_messages = 0
|
||||||
for message in reversed(MESSAGES):
|
for message in reversed(MESSAGES):
|
||||||
message_sent_ago = timestamp - message['timestamp']
|
message_sent_ago = timestamp - message['timestamp']
|
||||||
|
|
|
@ -50,3 +50,13 @@ def get_user_for_websocket(user):
|
||||||
**{key: user[key] for key in USER_WEBSOCKET_ATTRS},
|
**{key: user[key] for key in USER_WEBSOCKET_ATTRS},
|
||||||
'watching': trilean(user['presence']),
|
'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))
|
||||||
|
|
|
@ -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.user import get_all_users_for_websocket, see, reading, verify, deverify, BadCaptcha, try_change_appearance
|
||||||
from anonstream.wrappers import with_timestamp
|
from anonstream.wrappers import with_timestamp
|
||||||
from anonstream.utils.chat import generate_nonce
|
from anonstream.utils.chat import generate_nonce
|
||||||
|
from anonstream.utils.user import identifying_string
|
||||||
from anonstream.utils.websocket import parse_websocket_data, Malformed, WS
|
from anonstream.utils.websocket import parse_websocket_data, Malformed, WS
|
||||||
|
|
||||||
CONFIG = current_app.config
|
CONFIG = current_app.config
|
||||||
|
@ -74,7 +75,7 @@ async def websocket_inbound(queue, user):
|
||||||
|
|
||||||
@with_timestamp()
|
@with_timestamp()
|
||||||
def handle_inbound_pong(timestamp, queue, user):
|
def handle_inbound_pong(timestamp, queue, user):
|
||||||
print(f'[pong] {user["token"]}')
|
print(f'[pong] {identifying_string(user)}')
|
||||||
reading(user, timestamp=timestamp)
|
reading(user, timestamp=timestamp)
|
||||||
user['websockets'][queue] = timestamp
|
user['websockets'][queue] = timestamp
|
||||||
return None
|
return None
|
||||||
|
|
読み込み中…
新しいイシューから参照