Merge branch 'dev'

このコミットが含まれているのは:
n9k 2022-06-17 00:41:01 +00:00
コミット 3080c002f5
11個のファイルの変更89行の追加46行の削除

ファイルの表示

@ -62,14 +62,21 @@ def add_chat_message(user, nonce, comment, ignore_empty=False):
raise Rejected('Message was empty')
if len(comment.strip()) == 0:
raise Rejected('Message was practically empty')
if len(comment) > 512:
raise Rejected('Message exceeded 512 chars')
if comment.count('\n') + 1 > 12:
raise Rejected('Message exceeded 12 lines')
if len(comment) > CONFIG['CHAT_COMMENT_MAX_LENGTH']:
raise Rejected(
f'Message exceeded {CONFIG["CHAT_COMMENT_MAX_LENGTH"]} chars'
)
if comment.count('\n') + 1 > CONFIG['CHAT_COMMENT_MAX_LINES']:
raise Rejected(
f'Message exceeded {CONFIG["CHAT_COMMENT_MAX_LINES"]} lines'
)
linespan = get_approx_linespan(comment)
if linespan > 12:
raise Rejected('Message would span too many lines')
if linespan > CONFIG['CHAT_COMMENT_MAX_LINES']:
raise Rejected(
f'Message would span {CONFIG["CHAT_COMMENT_MAX_LINES"]} '
f'or more lines'
)
# Record linespan
linespan_tuple = (timestamp, linespan)

ファイルの表示

@ -33,10 +33,11 @@ def toml_to_flask_sections(config):
toml_to_flask_section_names,
toml_to_flask_section_memory,
toml_to_flask_section_tasks,
toml_to_flask_section_thresholds,
toml_to_flask_section_presence,
toml_to_flask_section_chat,
toml_to_flask_section_flood,
toml_to_flask_section_captcha,
toml_to_flask_section_nojs,
)
for toml_to_flask_section in TOML_TO_FLASK_SECTIONS:
yield toml_to_flask_section(config)
@ -103,23 +104,24 @@ def toml_to_flask_section_tasks(config):
'TASK_BROADCAST_STREAM_INFO_UPDATE': cfg['broadcast_stream_info_update'],
}
def toml_to_flask_section_thresholds(config):
cfg = config['thresholds']
assert cfg['user_notwatching'] <= cfg['user_tentative'] <= cfg['user_absent']
def toml_to_flask_section_presence(config):
cfg = config['presence']
assert cfg['notwatching'] <= cfg['tentative'] <= cfg['absent']
return {
'THRESHOLD_USER_NOTWATCHING': cfg['user_notwatching'],
'THRESHOLD_USER_TENTATIVE': cfg['user_tentative'],
'THRESHOLD_USER_ABSENT': cfg['user_absent'],
'THRESHOLD_NOJS_CHAT_TIMEOUT': cfg['nojs_chat_timeout'],
'PRESENCE_NOTWATCHING': cfg['notwatching'],
'PRESENCE_TENTATIVE': cfg['tentative'],
'PRESENCE_ABSENT': cfg['absent'],
}
def toml_to_flask_section_chat(config):
cfg = config['chat']
return {
'CHAT_COMMENT_MAX_LENGTH': cfg['max_name_length'],
'CHAT_COMMENT_MAX_LENGTH': cfg['max_comment_length'],
'CHAT_COMMENT_MAX_LINES': cfg['max_comment_lines'],
'CHAT_NAME_MAX_LENGTH': cfg['max_name_length'],
'CHAT_NAME_MIN_CONTRAST': cfg['min_name_contrast'],
'CHAT_BACKGROUND_COLOUR': color_to_colour(cfg['background_color']),
'CHAT_TRIPCODE_PASSWORD_MAX_LENGTH': cfg['max_tripcode_password_length'],
'CHAT_LEGACY_TRIPCODE_ALGORITHM': cfg['legacy_tripcode_algorithm'],
}
@ -147,3 +149,12 @@ def toml_to_flask_section_captcha(config):
'CAPTCHA_BACKGROUND_COLOUR': color_to_colour(cfg['background_color']),
'CAPTCHA_FOREGROUND_COLOUR': color_to_colour(cfg['foreground_color']),
}
def toml_to_flask_section_nojs(config):
cfg = config['nojs']
return {
'NOJS_REFRESH_MESSAGES': round(cfg['refresh_messages']),
'NOJS_REFRESH_INFO': round(cfg['refresh_info']),
'NOJS_REFRESH_USERS': round(cfg['refresh_users']),
'NOJS_TIMEOUT_CHAT': round(cfg['timeout_chat']),
}

ファイルの表示

@ -62,16 +62,16 @@ def get_default_name(user):
def get_presence(timestamp, user):
last_watching_ago = timestamp - user['last']['watching']
if last_watching_ago < CONFIG['THRESHOLD_USER_NOTWATCHING']:
if last_watching_ago < CONFIG['PRESENCE_NOTWATCHING']:
return Presence.WATCHING
last_seen_ago = timestamp - user['last']['seen']
if last_seen_ago < CONFIG['THRESHOLD_USER_TENTATIVE']:
if last_seen_ago < CONFIG['PRESENCE_TENTATIVE']:
return Presence.NOTWATCHING
if user['websockets']:
return Presence.NOTWATCHING
if last_seen_ago < CONFIG['THRESHOLD_USER_ABSENT']:
if last_seen_ago < CONFIG['PRESENCE_ABSENT']:
return Presence.TENTATIVE
return Presence.ABSENT

ファイルの表示

@ -35,6 +35,7 @@ async def nojs_info(user):
return await render_template(
'nojs_info.html',
csp=generate_csp(),
refresh=CONFIG['NOJS_REFRESH_INFO'],
user=user,
viewership=viewership,
uptime=uptime,
@ -48,10 +49,11 @@ async def nojs_chat_messages(user):
return await render_template_with_etag(
'nojs_chat_messages.html',
{'csp': generate_csp()},
refresh=CONFIG['NOJS_REFRESH_MESSAGES'],
user=user,
users_by_token=USERS_BY_TOKEN,
messages=get_scrollback(current_app.messages),
timeout=CONFIG['THRESHOLD_NOJS_CHAT_TIMEOUT'],
timeout=CONFIG['NOJS_TIMEOUT_CHAT'],
get_default_name=get_default_name,
)
@ -67,11 +69,12 @@ async def nojs_chat_users(user):
return await render_template_with_etag(
'nojs_chat_users.html',
{'csp': generate_csp()},
refresh=CONFIG['NOJS_REFRESH_USERS'],
user=user,
get_default_name=get_default_name,
users_watching=users_by_presence[Presence.WATCHING],
users_notwatching=users_by_presence[Presence.NOTWATCHING],
timeout=CONFIG['THRESHOLD_NOJS_CHAT_TIMEOUT'],
timeout=CONFIG['NOJS_TIMEOUT_CHAT'],
)
@current_app.route('/chat/form.html')
@ -89,20 +92,22 @@ async def nojs_chat_form(user):
nonce=generate_nonce(),
digest=get_random_captcha_digest_for(user),
default_name=get_default_name(user),
max_comment_length=CONFIG['CHAT_COMMENT_MAX_LENGTH'],
max_name_length=CONFIG['CHAT_NAME_MAX_LENGTH'],
max_password_length=CONFIG['CHAT_TRIPCODE_PASSWORD_MAX_LENGTH'],
)
@current_app.post('/chat/form')
@with_user_from(request)
async def nojs_chat_form_redirect(user):
comment = (await request.form).get('comment', '')
if len(comment) > CONFIG['CHAT_COMMENT_MAX_LENGTH']:
comment = ''
if comment:
state_id = add_state(user, comment=comment)
state_id = add_state(
user,
comment=comment[:CONFIG['CHAT_COMMENT_MAX_LENGTH']],
)
else:
state_id = None
return redirect(url_for('nojs_chat_form', token=user['token'], state=state_id))
@current_app.post('/chat/message')
@ -117,7 +122,11 @@ async def nojs_submit_message(user):
verification_happened = verify(user, digest, answer)
except BadCaptcha as e:
notice, *_ = e.args
state_id = add_state(user, notice=notice, comment=comment)
state_id = add_state(
user,
notice=notice,
comment=comment[:CONFIG['CHAT_COMMENT_MAX_LENGTH']],
)
else:
nonce = form.get('nonce', '')
try:
@ -131,7 +140,11 @@ async def nojs_submit_message(user):
)
except Rejected as e:
notice, *_ = e.args
state_id = add_state(user, notice=notice, comment=comment)
state_id = add_state(
user,
notice=notice,
comment=comment[:CONFIG['CHAT_COMMENT_MAX_LENGTH']],
)
else:
state_id = None
if message_was_added:

ファイルの表示

@ -33,7 +33,7 @@ const jsmarkup_chat_users = `\
const jsmarkup_chat_form = `\
<form id="chat-form_js" data-js="true" action="/chat" method="post">
<input id="chat-form_js__nonce" type="hidden" name="nonce" value="">
<textarea id="chat-form_js__comment" name="comment" maxlength="512" required placeholder="Send a message..." rows="1" autofocus></textarea>
<textarea id="chat-form_js__comment" name="comment" required placeholder="Send a message..." rows="1" autofocus></textarea>
<div id="chat-live">
<span id="chat-live__ball"></span>
<span id="chat-live__status">
@ -55,10 +55,10 @@ const jsmarkup_chat_form = `\
</form>
<form id="appearance-form_js" data-hidden="">
<span id="appearance-form_js__label-name">Name:</span>
<input id="appearance-form_js__name" name="name" maxlength="24">
<input id="appearance-form_js__name" name="name">
<input id="appearance-form_js__color" type="color" name="color">
<span id="appearance-form_js__label-tripcode">Tripcode:</span>
<input id="appearance-form_js__password" type="password" name="password" placeholder="(tripcode password)" maxlength="1024">
<input id="appearance-form_js__password" type="password" name="password" placeholder="(tripcode password)">
<div id="appearance-form_js__row">
<article id="appearance-form_js__row__result"></article>
<input id="appearance-form_js__row__submit" type="submit" value="Update">

ファイルの表示

@ -220,7 +220,7 @@
{% endif %}
<form id="chat-form" action="{{ url_for('nojs_submit_message', token=user.token) }}" method="post">
<input type="hidden" name="nonce" value="{{ nonce }}">
<textarea id="chat-form__comment" name="comment" maxlength="512" {% if digest is none %}required {% endif %} placeholder="Send a message..." rows="1" tabindex="1" autofocus accesskey="m">{{ state.comment }}</textarea>
<textarea id="chat-form__comment" name="comment" maxlength="{{ max_comment_length }}" {% if digest is none %}required {% endif %} placeholder="Send a message..." rows="1" tabindex="1" autofocus accesskey="m">{{ state.comment }}</textarea>
<input id="chat-form__submit" type="submit" value="Chat" tabindex="4" accesskey="p">
<div id="chat-form__exit"><label for="toggle" class="pseudolink">Settings</label></div>
{% if digest %}
@ -231,7 +231,7 @@
</form>
<form id="appearance-form" action="{{ url_for('nojs_submit_appearance', token=user.token) }}" method="post">
<label id="appearance-form__label-name" for="appearance-form__name">Name:</label>
<input id="appearance-form__name" name="name" value="{{ user.name or '' }}" placeholder="{{ default_name }}" maxlength="24">
<input id="appearance-form__name" name="name" value="{{ user.name or '' }}" placeholder="{{ default_name }}" maxlength="{{ max_name_length }}">
<input type="color" name="color" value="{{ user.color }}">
<label id="appearance-form__label-password" for="appearance-form__password">Tripcode:</label>
<input id="password-toggle" name="set-tripcode" type="checkbox" accesskey="s">
@ -247,7 +247,7 @@
<label id="hide-cleared" for="cleared-toggle" class="pseudolink">undo</label>
{% endif %}
</div>
<input id="appearance-form__password" name="password" type="password" placeholder="(tripcode password)" maxlength="1024">
<input id="appearance-form__password" name="password" type="password" placeholder="(tripcode password)" maxlength="{{ max_password_length }}">
<div id="hide-password"><label for="password-toggle" class="pseudolink x">&times;</label></div>
<div id="appearance-form__buttons">
<div id="appearance-form__buttons__exit"><label for="toggle" class="pseudolink">Return to chat</label></div>

ファイルの表示

@ -9,8 +9,8 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-security-policy" content="default-src 'none'; style-src 'nonce-{{ csp }}';">
<meta http-equiv="refresh" content="4">
<meta http-equiv="refresh" content="5; url={{ url_for('nojs_chat_messages_redirect', token=user.token) }}">
<meta http-equiv="refresh" content="{{ refresh }}">
<meta http-equiv="refresh" content="{{ refresh + 1 }}; url={{ url_for('nojs_chat_messages_redirect', token=user.token) }}">
<style nonce="{{ csp }}">
html {
height: 100%;

ファイルの表示

@ -9,7 +9,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-security-policy" content="default-src 'none'; style-src 'nonce-{{ csp }}';">
<meta http-equiv="refresh" content="6">
<meta http-equiv="refresh" content="{{ refresh }}">
<style nonce="{{ csp }}">
html {
min-height: 100%;

ファイルの表示

@ -8,7 +8,7 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="content-security-policy" content="default-src 'none'; style-src 'nonce-{{ csp }}';">
<meta http-equiv="refresh" content="6">
<meta http-equiv="refresh" content="{{ refresh }}">
<style nonce="{{ csp }}">
body {
overflow-y: auto;

ファイルの表示

@ -93,8 +93,10 @@ def change_name(user, name, dry_run=False):
if name is not None:
if len(name) == 0:
raise BadAppearance('Name was empty')
if len(name) > 24:
raise BadAppearance('Name exceeded 24 chars')
if len(name) > CONFIG['CHAT_NAME_MAX_LENGTH']:
raise BadAppearance(
f'Name exceeded {CONFIG["CHAT_NAME_MAX_LENGTH"]} chars'
)
else:
user['name'] = name
@ -119,8 +121,11 @@ def change_color(user, color, dry_run=False):
def change_tripcode(user, password, dry_run=False):
if dry_run:
if len(password) > 1024:
raise BadAppearance('Password exceeded 1024 chars')
if len(password) > CONFIG['CHAT_TRIPCODE_PASSWORD_MAX_LENGTH']:
raise BadAppearance(
f'Password exceeded '
f'{CONFIG["CHAT_TRIPCODE_PASSWORD_MAX_LENGTH"]} chars'
)
else:
user['tripcode'] = generate_tripcode(password)

ファイルの表示

@ -53,9 +53,11 @@ anonymous = "Anonymous"
[chat]
max_comment_length = 512
max_comment_lines = 12
max_name_length = 24
min_name_contrast = 3.0
background_color = "#232327"
max_tripcode_password_length = 1024
legacy_tripcode_algorithm = false
[flood.messages]
@ -72,8 +74,13 @@ cooldown = 12.0
expire_after = 5.0
overwrite = true
[thresholds]
user_notwatching = 8.0
user_tentative = 20.0
user_absent = 360.0
nojs_chat_timeout = 30.0
[presence]
notwatching = 8.0
tentative = 20.0
absent = 360.0
[nojs]
refresh_messages = 4.0
refresh_info = 6.0
refresh_users = 6.0
timeout_chat = 30.0