Merge branch 'dev'
このコミットが含まれているのは:
コミット
b09c396d1c
|
@ -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:
|
||||||
|
|
読み込み中…
新しいイシューから参照