Merge pull request 'Rework the captcha to correctly reset after a post' (#158) from captcha-rework into config

Reviewed-on: https://git.leftypol.org/leftypol/leftypol/pulls/158
This commit is contained in:
Zankaria 2024-08-07 19:32:23 +00:00
commit ed330a009c
6 changed files with 187 additions and 145 deletions

View file

@ -0,0 +1,3 @@
{% if config.turnstile %}
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit&onload=onCaptchaLoadTurnstile_{{ form_action_type }}" async defer></script>
{% endif %}

View file

@ -13,9 +13,7 @@
active_page = "ukko";
{% endif %}
</script>
{% if config.turnstile %}
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
{% endif %}
{{ include('captcha_script.html', { form_action_type: 'post_thread' }) }}
{% include 'header.html' %}
{% set page_num %}{% for page in pages %}{% if page.selected %}{% if page.num != 1 %}{{ page.num }}{% endif %}{% endif %}{% endfor %}{% endset %}
@ -61,7 +59,7 @@
{{ config.ad.top }}
{% if not no_post_form %}
{{ include('post_form.html', {form_action_type: 'post-thread'}) }}
{% include 'post_form.html' %}
{% else %}
{% include 'boardlist.html' %}
{% endif %}

View file

@ -22,39 +22,39 @@ function fmt(s,a) {
return s.replace(/\{([0-9]+)\}/g, function(x) { return a[x[1]]; });
}
function until($timestamp) {
var $difference = $timestamp - Date.now()/1000|0, $num;
function until(timestamp) {
let difference = timestamp - Date.now() / 1000 | 0;
switch (true) {
case ($difference < 60):
return "" + $difference + ' ' + _('second(s)');
case ($difference < 3600): //60*60 = 3600
return "" + ($num = Math.round($difference/(60))) + ' ' + _('minute(s)');
case ($difference < 86400): //60*60*24 = 86400
return "" + ($num = Math.round($difference/(3600))) + ' ' + _('hour(s)');
case ($difference < 604800): //60*60*24*7 = 604800
return "" + ($num = Math.round($difference/(86400))) + ' ' + _('day(s)');
case ($difference < 31536000): //60*60*24*365 = 31536000
return "" + ($num = Math.round($difference/(604800))) + ' ' + _('week(s)');
case (difference < 60):
return "" + difference + ' ' + _('second(s)');
case (difference < 3600): // 60 * 60 = 3600
return "" + Math.round(difference / 60) + ' ' + _('minute(s)');
case (difference < 86400): // 60 * 60 * 24 = 86400
return "" + Math.round(difference / 3600) + ' ' + _('hour(s)');
case (difference < 604800): // 60 * 60 * 24 * 7 = 604800
return "" + Math.round(difference / 86400) + ' ' + _('day(s)');
case (difference < 31536000): // 60 * 60 * 24 * 365 = 31536000
return "" + Math.round(difference / 604800) + ' ' + _('week(s)');
default:
return "" + ($num = Math.round($difference/(31536000))) + ' ' + _('year(s)');
return "" + Math.round(difference / 31536000) + ' ' + _('year(s)');
}
}
function ago($timestamp) {
var $difference = (Date.now()/1000|0) - $timestamp, $num;
function ago(timestamp) {
let difference = (Date.now() / 1000 | 0) - timestamp;
switch (true) {
case ($difference < 60) :
return "" + $difference + ' ' + _('second(s)');
case ($difference < 3600): //60*60 = 3600
return "" + ($num = Math.round($difference/(60))) + ' ' + _('minute(s)');
case ($difference < 86400): //60*60*24 = 86400
return "" + ($num = Math.round($difference/(3600))) + ' ' + _('hour(s)');
case ($difference < 604800): //60*60*24*7 = 604800
return "" + ($num = Math.round($difference/(86400))) + ' ' + _('day(s)');
case ($difference < 31536000): //60*60*24*365 = 31536000
return "" + ($num = Math.round($difference/(604800))) + ' ' + _('week(s)');
case (difference < 60):
return "" + difference + ' ' + _('second(s)');
case (difference < 3600): /// 60 * 60 = 3600
return "" + Math.round(difference/(60)) + ' ' + _('minute(s)');
case (difference < 86400): // 60 * 60 * 24 = 86400
return "" + Math.round(difference/(3600)) + ' ' + _('hour(s)');
case (difference < 604800): // 60 * 60 * 24 * 7 = 604800
return "" + Math.round(difference/(86400)) + ' ' + _('day(s)');
case (difference < 31536000): // 60 * 60 * 24 * 365 = 31536000
return "" + Math.round(difference/(604800)) + ' ' + _('week(s)');
default:
return "" + ($num = Math.round($difference/(31536000))) + ' ' + _('year(s)');
return "" + Math.round(difference/(31536000)) + ' ' + _('year(s)');
}
}
@ -72,7 +72,7 @@ var datelocale =
function alert(a, do_confirm, confirm_ok_action, confirm_cancel_action) {
var handler, div, bg, closebtn, okbtn;
var close = function() {
let close = function() {
handler.fadeOut(400, function() { handler.remove(); });
return false;
};
@ -173,9 +173,10 @@ function changeStyle(styleName, link) {
link.className = 'selected';
}
if (typeof $ != 'undefined')
if (typeof $ != 'undefined') {
$(window).trigger('stylesheet', styleName);
}
}
{% endraw %}
@ -210,7 +211,7 @@ function changeStyle(styleName, link) {
{% endif %}
{% raw %}
function init_stylechooser() {
function initStyleChooser() {
var newElement = document.createElement('div');
newElement.className = 'styles';
@ -230,45 +231,77 @@ function init_stylechooser() {
document.getElementById('bottom-hud').before(newElement);
}
function get_cookie(cookie_name) {
var results = document.cookie.match('(^|;) ?' + cookie_name + '=([^;]*)(;|$)');
if (results)
return (unescape(results[2]));
else
function getCookie(cookie_name) {
let results = document.cookie.match('(^|;) ?' + cookie_name + '=([^;]*)(;|$)');
if (results) {
return unescape(results[2]);
} else {
return null;
}
}
{% endraw %}
{% if config.turnstile %}
// Wrapper function to be called from thread.html
window.onCaptchaLoadTurnstile_post_reply = function() {
onCaptchaLoadTurnstile('post-reply');
}
// Wrapper function to be called from index.html and catalog.html
window.onCaptchaLoadTurnstile_post_thread = function() {
onCaptchaLoadTurnstile('post-thread');
}
// Should be called by the captcha API when it's ready. Ugly I know... D:
function onCaptchaLoadTurnstile(action) {
let renderer = {
renderOn: function(container) {
let widgetId = turnstile.render(container, {
sitekey: "{{ config.turnstile_public }}",
action: action,
});
if (widgetId === undefined) {
return null;
}
return widgetId;
},
remove: function(widgetId) {
turnstile.remove(widgetId);
},
reset: function(widgetId) {
turnstile.reset(widgetId);
}
};
onCaptchaLoad(renderer);
}
{% endif %}
function onCaptchaLoad(renderer) {
let widgetId = renderer.renderOn('#captcha-container');
if (widgetId === null) {
console.error('Could not render captcha!');
}
document.addEventListener('afterdopost', function(e) {
// User posted! Reset the captcha.
renderer.reset(widgetId);
});
}
{% if config.dynamic_captcha %}
function is_dynamic_captcha_enabled() {
let cookie = get_cookie('captcha-required');
function isDynamicCaptchaEnabled() {
let cookie = getCookie('captcha-required');
return cookie === '1';
}
function get_captcha_pub_key() {
{% if config.recaptcha %}
return "{{ config.recaptcha_public }}";
{% elseif config.turnstile_public %}
return "{{ config.turnstile_public }}";
{% else %}
return null;
{% endif %}
}
function init_dynamic_captcha() {
if (is_dynamic_captcha_enabled()) {
let pub_key = get_captcha_pub_key();
if (!pub_key) {
console.error("Missing public captcha key!");
return;
}
function initDynamicCaptcha() {
if (isDynamicCaptchaEnabled()) {
let captcha_hook = document.getElementById('captcha');
captcha_hook.style = "";
}
}
{% else %}
function init_dynamic_captcha() {}
function initDynamicCaptcha() {}
{% endif %}
{% raw %}
@ -278,32 +311,34 @@ function highlightReply(id) {
return true;
}
var divs = document.getElementsByTagName('div');
let divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++)
{
if (divs[i].className.indexOf('post') != -1)
if (divs[i].className.indexOf('post') != -1) {
divs[i].className = divs[i].className.replace(/highlighted/, '');
}
}
if (id) {
var post = document.getElementById('reply_'+id);
if (post)
let post = document.getElementById('reply_' + id);
if (post) {
post.className += ' highlighted';
}
window.location.hash = id;
}
return true;
}
function generatePassword() {
var pass = '';
var chars = '{% endraw %}{{ config.genpassword_chars }}{% raw %}';
for (var i = 0; i < 8; i++) {
var rnd = Math.floor(Math.random() * chars.length);
let pass = '';
let chars = '{% endraw %}{{ config.genpassword_chars }}{% raw %}';
for (let i = 0; i < 8; i++) {
let rnd = Math.floor(Math.random() * chars.length);
pass += chars.substring(rnd, rnd + 1);
}
return pass;
}
function dopost(form) {
function doPost(form) {
if (form.elements['name']) {
localStorage.name = form.elements['name'].value.replace(/( |^)## .+$/, '');
}
@ -317,6 +352,8 @@ function dopost(form) {
saved[document.location] = form.elements['body'].value;
sessionStorage.body = JSON.stringify(saved);
// Needs to be delayed by at least 1 frame, otherwise it may reset the form (read captcha) fields before they're sent.
setTimeout(() => document.dispatchEvent(new Event('afterdopost')));
return form.elements['body'].value != "" || (form.elements['file'] && form.elements['file'].value != "") || (form.elements.file_url && form.elements['file_url'].value != "");
}
@ -324,26 +361,29 @@ function reloadCaptcha() {
// Reload captcha images (date reduces chance of caching)
// If no securimage captcha is enabled, no elements will be found
captchaImgs = document.querySelectorAll('[id=captcha-img]');
for (var i = 0; i < captchaImgs.length; ++i)
for (let i = 0; i < captchaImgs.length; ++i) {
captchaImgs[i].src = "/captcha.php?" + Date.now();
}
captchas = document.querySelectorAll('[id=captcha]');
for (var i = 0; i < captchas.length; ++i)
for (let i = 0; i < captchas.length; ++i) {
captchas[i].value = "";
}
}
function citeReply(id, with_link) {
var textarea = document.getElementById('body');
if (!textarea) return false;
let textarea = document.getElementById('body');
if (!textarea) {
return false;
}
if (document.selection) {
// IE
textarea.focus();
var sel = document.selection.createRange();
let sel = document.selection.createRange();
sel.text = '>>' + id + '\n';
} else if (textarea.selectionStart || textarea.selectionStart == '0') {
var start = textarea.selectionStart;
var end = textarea.selectionEnd;
let start = textarea.selectionStart;
let end = textarea.selectionEnd;
textarea.value = textarea.value.substring(0, start) + '>>' + id + '\n' + textarea.value.substring(end, textarea.value.length);
textarea.selectionStart += ('>>' + id).length + 1;
@ -353,9 +393,9 @@ function citeReply(id, with_link) {
textarea.value += '>>' + id + '\n';
}
if (typeof $ != 'undefined') {
var select = document.getSelection().toString();
let select = document.getSelection().toString();
if (select) {
var body = $('#reply_' + id + ', #op_' + id).find('div.body'); // TODO: support for OPs
let body = $('#reply_' + id + ', #op_' + id).find('div.body'); // TODO: support for OPs
// commenting out this condition, not sure of the purpose and gets in the way of citing
// var index = body.text().indexOf(select.replace('\n', '')); // for some reason this only works like this
// if (index > -1) {
@ -374,25 +414,29 @@ function citeReply(id, with_link) {
function rememberStuff() {
if (document.forms.post) {
if (document.forms.post.password) {
if (!localStorage.password)
if (!localStorage.password) {
localStorage.password = generatePassword();
}
document.forms.post.password.value = localStorage.password;
}
if (localStorage.name && document.forms.post.elements['name'])
if (localStorage.name && document.forms.post.elements['name']) {
document.forms.post.elements['name'].value = localStorage.name;
if (localStorage.email && document.forms.post.elements['email'])
}
if (localStorage.email && document.forms.post.elements['email']) {
document.forms.post.elements['email'].value = localStorage.email;
}
if (window.location.hash.indexOf('q') == 1)
if (window.location.hash.indexOf('q') == 1) {
citeReply(window.location.hash.substring(2), true);
}
if (sessionStorage.body) {
var saved = JSON.parse(sessionStorage.body);
if (get_cookie('{% endraw %}{{ config.cookies.js }}{% raw %}')) {
let saved = JSON.parse(sessionStorage.body);
if (getCookie('{% endraw %}{{ config.cookies.js }}{% raw %}')) {
// Remove successful posts
var successful = JSON.parse(get_cookie('{% endraw %}{{ config.cookies.js }}{% raw %}'));
for (var url in successful) {
let successful = JSON.parse(getCookie('{% endraw %}{{ config.cookies.js }}{% raw %}'));
for (let url in successful) {
saved[url] = null;
}
sessionStorage.body = JSON.stringify(saved);
@ -416,15 +460,16 @@ var script_settings = function(script_name) {
this.get = function(var_name, default_val) {
if (typeof tb_settings == 'undefined' ||
typeof tb_settings[this.script_name] == 'undefined' ||
typeof tb_settings[this.script_name][var_name] == 'undefined')
typeof tb_settings[this.script_name][var_name] == 'undefined') {
return default_val;
}
return tb_settings[this.script_name][var_name];
}
};
function init() {
init_stylechooser();
init_dynamic_captcha();
initStyleChooser();
initDynamicCaptcha();
{% endraw %}
{% if config.allow_delete %}
@ -443,12 +488,12 @@ var RecaptchaOptions = {
};
onready_callbacks = [];
function onready(fnc) {
function onReady(fnc) {
onready_callbacks.push(fnc);
}
function ready() {
for (var i = 0; i < onready_callbacks.length; i++) {
for (let i = 0; i < onready_callbacks.length; i++) {
onready_callbacks[i]();
}
}
@ -458,7 +503,7 @@ function ready() {
var post_date = "{{ config.post_date }}";
var max_images = {{ config.max_images }};
onready(init);
onReady(init);
{% if config.google_analytics %}{% raw %}

View file

@ -1,5 +1,5 @@
<form
name="post" onsubmit="return dopost(this);"
name="post" onsubmit="return doPost(this);"
enctype="multipart/form-data"
action="{{ config.post_url }}"
method="post"
@ -117,7 +117,7 @@
{{ antibot.html() }}
</th>
<td>
<div class="cf-turnstile" data-sitekey="{{ config.turnstile_public }}" data-action="{{ form_action_type }}"></div>
<div id="captcha-container"></div>
{{ antibot.html() }}
</td>
</tr>

View file

@ -9,9 +9,7 @@
, board_name = "{{ board.uri }}"
, is_overboard = "{{ is_overboard }}";
</script>
{% if config.turnstile %}
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
{% endif %}
{{ include('captcha_script.html', { form_action_type: 'post_thread' }) }}
<title>{{ settings.title }} ( /{{ board.title|e }}/ )</title>
{% include 'header.html' %}
</head>
@ -31,7 +29,7 @@
<center>[ {% trans 'Create new thread' %} ]</center>
</summary>
<div style="margin: 1em 0;">
{{ include('post_form.html', {form_action_type: 'post-thread'}) }}
{% include 'post_form.html' %}
</div>
</details>
{% endif %}

View file

@ -8,9 +8,7 @@
, board_name = "{{ board.uri }}"
, thread_id = "{{ thread.id }}";
</script>
{% if config.turnstile %}
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
{% endif %}
{{ include('captcha_script.html', { form_action_type: 'post_reply' }) }}
{% include 'header.html' %}
@ -56,7 +54,7 @@
{{ config.ad.top }}
{{ include('post_form.html', {form_action_type: 'post-reply'}) }}
{% include 'post_form.html' %}
{% if config.global_message %}<hr /><div class="blotter">{{ config.global_message }}</div>{% endif %}
<hr />