Merge branch 'dev'
このコミットが含まれているのは:
コミット
3080c002f5
|
@ -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">×</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)
|
||||
|
||||
|
|
17
config.toml
17
config.toml
|
@ -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
|
||||
|
|
読み込み中…
新しいイシューから参照