Merge branch 'dev'

このコミットが含まれているのは:
n9k 2022-06-25 07:45:31 +00:00
コミット b09c396d1c
8個のファイルの変更58行の追加22行の削除

ファイルの表示

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2022 n9k <https://git.076.ne.jp/ninya9k>
# SPDX-License-Identifier: AGPL-3.0-or-later
import argparse import argparse
import os import os

ファイルの表示

@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: 2022 n9k <https://git.076.ne.jp/ninya9k>
# SPDX-License-Identifier: AGPL-3.0-or-later
import time import time
from quart import current_app from quart import current_app

ファイルの表示

@ -46,7 +46,7 @@ async def cmd_user_help():
' user [show]...................show all users\' tokens\n' ' user [show]...................show all users\' tokens\n'
' user attr USER................show names of a user\'s attributes\n' ' user attr USER................show names of a user\'s attributes\n'
' user get USER ATTR............show an attribute of a user\n' ' user get USER ATTR............show an attribute of a user\n'
' user set USER ATTR............set an attribute of a user\n' ' user set USER ATTR VALUE......set an attribute of a user\n'
' user eyes USER [show].........show a user\'s active video responses\n' ' user eyes USER [show].........show a user\'s active video responses\n'
' user eyes USER delete EYES_ID.end a video response to a user\n' ' user eyes USER delete EYES_ID.end a video response to a user\n'
'Definitions:\n' 'Definitions:\n'
@ -54,6 +54,7 @@ async def cmd_user_help():
' TOKEN.........................a token, json string\n' ' TOKEN.........................a token, json string\n'
' HASH..........................a token hash\n' ' HASH..........................a token hash\n'
' ATTR..........................a user attribute, re:[a-z0-9_]+\n' ' ATTR..........................a user attribute, re:[a-z0-9_]+\n'
' VALUE.........................json value\n'
' EYES_ID.......................a user\'s eyes_id, base 10 integer\n' ' EYES_ID.......................a user\'s eyes_id, base 10 integer\n'
) )
return normal, response return normal, response

ファイルの表示

@ -4,7 +4,7 @@
import asyncio import asyncio
from quart import current_app, websocket from quart import current_app, websocket
from anonstream.user import see, reading from anonstream.user import see
from anonstream.websocket import websocket_outbound, websocket_inbound from anonstream.websocket import websocket_outbound, websocket_inbound
from anonstream.routes.wrappers import with_user_from from anonstream.routes.wrappers import with_user_from
@ -18,7 +18,7 @@ async def live(timestamp, user_or_token):
case dict() as user: case dict() as user:
queue = asyncio.Queue() queue = asyncio.Queue()
user['websockets'][queue] = timestamp user['websockets'][queue] = timestamp
reading(user, timestamp=timestamp) user['last']['reading'] = timestamp
producer = websocket_outbound(queue, user) producer = websocket_outbound(queue, user)
consumer = websocket_inbound(queue, user) consumer = websocket_inbound(queue, user)

ファイルの表示

@ -13,7 +13,6 @@ from werkzeug.exceptions import BadRequest, Unauthorized, Forbidden
from werkzeug.security import check_password_hash from werkzeug.security import check_password_hash
from anonstream.broadcast import broadcast from anonstream.broadcast import broadcast
from anonstream.user import see
from anonstream.helpers.user import generate_user from anonstream.helpers.user import generate_user
from anonstream.utils.user import generate_token, Presence from anonstream.utils.user import generate_token, Presence
from anonstream.wrappers import get_timestamp from anonstream.wrappers import get_timestamp
@ -121,7 +120,9 @@ def with_user_from(context, fallback_to_token=False):
raise Unauthorized(Markup( raise Unauthorized(Markup(
f"You are using the broadcaster's token but you are " f"You are using the broadcaster's token but you are "
f"not logged in. The broadcaster should " f"not logged in. The broadcaster should "
f"<a href=\"{url_for('login')}\">click here</a> " f"<a href=\"{url_for('login')}\" target=\"_top\">"
f"click here"
f"</a> "
f"and log in with the credentials printed in their " f"and log in with the credentials printed in their "
f"terminal when they started anonstream." f"terminal when they started anonstream."
)) ))
@ -138,12 +139,14 @@ def with_user_from(context, fallback_to_token=False):
else: else:
raise Forbidden(Markup( raise Forbidden(Markup(
f"You have not solved the access captcha. " f"You have not solved the access captcha. "
f"<a href=\"{url_for('home', token=token)}\">" f"<a href=\"{url_for('home', token=token)}\" target=\"_top\">"
f"Click here." f"Click here."
f"</a>" f"</a>"
)) ))
else: else:
if user is None: if user is not None:
user['last']['seen'] = timestamp
else:
user = generate_and_add_user(timestamp, token, broadcaster) user = generate_and_add_user(timestamp, token, broadcaster)
response = await f(timestamp, user, *args, **kwargs) response = await f(timestamp, user, *args, **kwargs)

ファイルの表示

@ -5,11 +5,11 @@
<title>{{ error.code }} {{ error.name }}</title> <title>{{ error.code }} {{ error.name }}</title>
<style> <style>
body { body {
background-color: #18181a; background-color: #232327;
color: #ddd; color: #ddd;
font-family: sans-serif; font-family: sans-serif;
font-size: 14pt; font-size: 14pt;
margin: 24pt 16pt; margin: 4pt 6pt;
text-align: center; text-align: center;
text-shadow: 2px 0px 1px orangered; text-shadow: 2px 0px 1px orangered;
} }
@ -19,6 +19,10 @@
} }
h1 { h1 {
font-size: 32pt; font-size: 32pt;
margin: 0 0 8pt;
}
p {
margin: 0;
} }
a { a {
color: #42a5d7; color: #42a5d7;
@ -29,11 +33,32 @@
border-radius: 2px; border-radius: 2px;
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
@media (min-height: 128px) {
body {
margin: 18pt 16pt;
}
h1 {
margin: revert;
}
p {
margin: revert;
}
}
@media (min-height: 192px) {
body {
margin: 24pt 16pt;
}
}
@media (min-width: 400px) and (min-height: 128px;) {
body {
background-color: #18181a;
}
}
</style> </style>
</head> </head>
<body> <body>
<main> <main>
<h1>{{ error.code }} {{ error.name }}</h1> <h1>{{ error.name }}</h1>
{% if error.description != error.__class__.description %} {% if error.description != error.__class__.description %}
<p>{{ error.description }}</p> <p>{{ error.description }}</p>
{% endif %} {% endif %}

ファイルの表示

@ -132,8 +132,9 @@ def change_tripcode(user, password, dry_run=False):
def delete_tripcode(user): def delete_tripcode(user):
user['tripcode'] = None user['tripcode'] = None
@with_timestamp() def see(user, timestamp=None):
def see(timestamp, user): if timestamp is None:
timestamp = get_timestamp()
user['last']['seen'] = timestamp user['last']['seen'] = timestamp
def watching(user, timestamp=None): def watching(user, timestamp=None):
@ -284,8 +285,8 @@ def create_eyes(timestamp, user, headers):
def renew_eyes(timestamp, user, eyes_id, just_read_new_segment=False): def renew_eyes(timestamp, user, eyes_id, just_read_new_segment=False):
try: try:
eyes = user['eyes']['current'][eyes_id] eyes = user['eyes']['current'][eyes_id]
except KeyError: except KeyError as e:
raise DeletedEyes raise DeletedEyes from e
# Enforce expire_after (if the background task hasn't already) # Enforce expire_after (if the background task hasn't already)
renewed_ago = timestamp - eyes['renewed'] renewed_ago = timestamp - eyes['renewed']

ファイルの表示

@ -10,7 +10,7 @@ from anonstream.stream import get_stream_title, get_stream_uptime_and_viewership
from anonstream.captcha import get_random_captcha_digest_for from anonstream.captcha import get_random_captcha_digest_for
from anonstream.chat import get_all_messages_for_websocket, add_chat_message, Rejected from anonstream.chat import get_all_messages_for_websocket, add_chat_message, Rejected
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, get_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.user import identifying_string
from anonstream.utils.websocket import parse_websocket_data, Malformed, WS from anonstream.utils.websocket import parse_websocket_data, Malformed, WS
@ -49,7 +49,8 @@ async def websocket_inbound(queue, user):
except json.JSONDecodeError: except json.JSONDecodeError:
receipt = None receipt = None
finally: finally:
see(user) timestamp = get_timestamp()
see(user, timestamp=timestamp)
try: try:
receipt_type, parsed = parse_websocket_data(receipt) receipt_type, parsed = parse_websocket_data(receipt)
except Malformed as e: except Malformed as e:
@ -68,25 +69,24 @@ async def websocket_inbound(queue, user):
handle = handle_inbound_captcha handle = handle_inbound_captcha
case WS.PONG: case WS.PONG:
handle = handle_inbound_pong handle = handle_inbound_pong
payload = handle(queue, user, *parsed) payload = handle(timestamp, queue, user, *parsed)
if payload is not None: if payload is not None:
queue.put_nowait(payload) queue.put_nowait(payload)
@with_timestamp()
def handle_inbound_pong(timestamp, queue, user): def handle_inbound_pong(timestamp, queue, user):
print(f'[pong] {identifying_string(user)}') print(f'[pong] {identifying_string(user)}')
reading(user, timestamp=timestamp) user['last']['reading'] = timestamp
user['websockets'][queue] = timestamp user['websockets'][queue] = timestamp
return None return None
def handle_inbound_captcha(queue, user): def handle_inbound_captcha(timestamp, queue, user):
return { return {
'type': 'captcha', 'type': 'captcha',
'digest': get_random_captcha_digest_for(user), 'digest': get_random_captcha_digest_for(user),
} }
def handle_inbound_appearance(queue, user, name, color, password, want_tripcode): def handle_inbound_appearance(timestamp, queue, user, name, color, password, want_tripcode):
errors = try_change_appearance(user, name, color, password, want_tripcode) errors = try_change_appearance(user, name, color, password, want_tripcode)
if errors: if errors:
return { return {
@ -102,7 +102,7 @@ def handle_inbound_appearance(queue, user, name, color, password, want_tripcode)
#'tripcode': user['tripcode'], #'tripcode': user['tripcode'],
} }
def handle_inbound_message(queue, user, nonce, comment, digest, answer): def handle_inbound_message(timestamp, queue, user, nonce, comment, digest, answer):
try: try:
verification_happened = verify(user, digest, answer) verification_happened = verify(user, digest, answer)
except BadCaptcha as e: except BadCaptcha as e: