mirror of
https://github.com/vichan-devel/vichan.git
synced 2025-01-09 13:01:45 +01:00
Merge pull request #858 from vichan-devel/removecurrentantibot
Remove current antibot system
This commit is contained in:
commit
b2ca26dba5
196
inc/anti-bot.php
196
inc/anti-bot.php
@ -1,199 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010-2013 Tinyboard Development Group
|
||||
* Anti-bot.php has been deprecated and removed due to its functions not being necessary and being easily bypassable, by both customized and uncustomized spambots.
|
||||
*/
|
||||
|
||||
defined('TINYBOARD') or exit;
|
||||
|
||||
class AntiBot {
|
||||
public $salt;
|
||||
public $inputs = [];
|
||||
public $index = 0;
|
||||
|
||||
public static function randomString($length, $uppercase = false, $special_chars = false, $unicode_chars = false) {
|
||||
$chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
|
||||
if ($uppercase) {
|
||||
$chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
}
|
||||
if ($special_chars) {
|
||||
$chars .= ' ~!@#$%^&*()_+,./;\'[]\\{}|:<>?=-` ';
|
||||
}
|
||||
if ($unicode_chars) {
|
||||
$len = strlen($chars) / 10;
|
||||
for ($n = 0; $n < $len; $n++) {
|
||||
$chars .= mb_convert_encoding('&#' . mt_rand(0x2600, 0x26FF) . ';', 'UTF-8', 'HTML-ENTITIES');
|
||||
}
|
||||
}
|
||||
|
||||
$chars = preg_split('//u', $chars, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
$ch = [];
|
||||
|
||||
// fill up $ch until we reach $length
|
||||
while (count($ch) < $length) {
|
||||
$n = $length - count($ch);
|
||||
$keys = array_rand($chars, $n > count($chars) ? count($chars) : $n);
|
||||
if ($n == 1) {
|
||||
$ch[] = $chars[$keys];
|
||||
break;
|
||||
}
|
||||
shuffle($keys);
|
||||
foreach ($keys as $key) {
|
||||
$ch[] = $chars[$key];
|
||||
}
|
||||
}
|
||||
|
||||
$chars = $ch;
|
||||
|
||||
return implode('', $chars);
|
||||
}
|
||||
|
||||
public static function make_confusing($string) {
|
||||
$chars = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
|
||||
|
||||
foreach ($chars as &$c) {
|
||||
if (mt_rand(0, 3) != 0) {
|
||||
$c = utf8tohtml($c);
|
||||
} else {
|
||||
$c = mb_encode_numericentity($c, [ 0, 0xffff, 0, 0xffff ], 'UTF-8');
|
||||
}
|
||||
}
|
||||
|
||||
return implode('', $chars);
|
||||
}
|
||||
|
||||
public function __construct(array $salt = []) {
|
||||
global $config;
|
||||
|
||||
if (!empty($salt)) {
|
||||
// Create a salted hash of the "extra salt"
|
||||
$this->salt = implode(':', $salt);
|
||||
} else {
|
||||
$this->salt = '';
|
||||
}
|
||||
|
||||
shuffle($config['spam']['hidden_input_names']);
|
||||
|
||||
$input_count = mt_rand($config['spam']['hidden_inputs_min'], $config['spam']['hidden_inputs_max']);
|
||||
$hidden_input_names_x = 0;
|
||||
|
||||
for ($x = 0; $x < $input_count ; $x++) {
|
||||
if ($hidden_input_names_x === false || mt_rand(0, 2) == 0) {
|
||||
// Use an obscure name
|
||||
$name = $this->randomString(mt_rand(10, 40), false, false, $config['spam']['unicode']);
|
||||
} else {
|
||||
// Use a pre-defined confusing name
|
||||
$name = $config['spam']['hidden_input_names'][$hidden_input_names_x++];
|
||||
if ($hidden_input_names_x >= count($config['spam']['hidden_input_names'])) {
|
||||
$hidden_input_names_x = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mt_rand(0, 2) == 0) {
|
||||
// Value must be null
|
||||
$this->inputs[$name] = '';
|
||||
} elseif (mt_rand(0, 4) == 0) {
|
||||
// Numeric value
|
||||
$this->inputs[$name] = (string)mt_rand(0, 100000);
|
||||
} else {
|
||||
// Obscure value
|
||||
$this->inputs[$name] = $this->randomString(mt_rand(5, 100), true, true, $config['spam']['unicode']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static function space() {
|
||||
if (mt_rand(0, 3) != 0) {
|
||||
return ' ';
|
||||
}
|
||||
return str_repeat(' ', mt_rand(1, 3));
|
||||
}
|
||||
|
||||
public function html($count = false) {
|
||||
$elements = [
|
||||
'<input type="hidden" name="%name%" value="%value%">',
|
||||
'<input type="hidden" value="%value%" name="%name%">',
|
||||
'<input name="%name%" value="%value%" type="hidden">',
|
||||
'<input value="%value%" name="%name%" type="hidden">',
|
||||
'<input style="display:none" type="text" name="%name%" value="%value%">',
|
||||
'<input style="display:none" type="text" value="%value%" name="%name%">',
|
||||
'<span style="display:none"><input type="text" name="%name%" value="%value%"></span>',
|
||||
'<div style="display:none"><input type="text" name="%name%" value="%value%"></div>',
|
||||
'<div style="display:none"><input type="text" name="%name%" value="%value%"></div>',
|
||||
'<textarea style="display:none" name="%name%">%value%</textarea>',
|
||||
'<textarea name="%name%" style="display:none">%value%</textarea>'
|
||||
];
|
||||
|
||||
$html = '';
|
||||
|
||||
if ($count === false) {
|
||||
$count = mt_rand(1, (int)abs(count($this->inputs) / 15) + 1);
|
||||
}
|
||||
|
||||
if ($count === true) {
|
||||
// All elements
|
||||
$inputs = array_slice($this->inputs, $this->index);
|
||||
} else {
|
||||
$inputs = array_slice($this->inputs, $this->index, $count);
|
||||
}
|
||||
$this->index += count($inputs);
|
||||
|
||||
foreach ($inputs as $name => $value) {
|
||||
$element = false;
|
||||
while (!$element) {
|
||||
$element = $elements[array_rand($elements)];
|
||||
$element = str_replace(' ', self::space(), $element);
|
||||
if (mt_rand(0, 5) == 0) {
|
||||
$element = str_replace('>', self::space() . '>', $element);
|
||||
}
|
||||
if (strpos($element, 'textarea') !== false && $value == '') {
|
||||
// There have been some issues with mobile web browsers and empty <textarea>'s.
|
||||
$element = false;
|
||||
}
|
||||
}
|
||||
|
||||
$element = str_replace('%name%', utf8tohtml($name), $element);
|
||||
|
||||
if (mt_rand(0, 2) == 0) {
|
||||
$value = $this->make_confusing($value);
|
||||
} else {
|
||||
$value = utf8tohtml($value);
|
||||
}
|
||||
|
||||
if (strpos($element, 'textarea') === false) {
|
||||
$value = str_replace('"', '"', $value);
|
||||
}
|
||||
|
||||
$element = str_replace('%value%', $value, $element);
|
||||
|
||||
$html .= $element;
|
||||
}
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function reset() {
|
||||
$this->index = 0;
|
||||
}
|
||||
|
||||
public function hash() {
|
||||
global $config;
|
||||
|
||||
// This is the tricky part: create a hash to validate it after
|
||||
// First, sort the keys in alphabetical order (A-Z)
|
||||
$inputs = $this->inputs;
|
||||
ksort($inputs);
|
||||
|
||||
$hash = '';
|
||||
// Iterate through each input
|
||||
foreach ($inputs as $name => $value) {
|
||||
$hash .= $name . '=' . $value;
|
||||
}
|
||||
// Add a salt to the hash
|
||||
$hash .= $config['cookies']['salt'];
|
||||
|
||||
// Use SHA1 for the hash
|
||||
return sha1($hash . $this->salt);
|
||||
}
|
||||
}
|
||||
|
@ -275,83 +275,6 @@
|
||||
// To prevent bump attacks; returns the thread to last position after the last post is deleted.
|
||||
$config['anti_bump_flood'] = false;
|
||||
|
||||
/*
|
||||
* Introduction to vichan's spam filter:
|
||||
*
|
||||
* In simple terms, whenever a posting form on a page is generated (which happens whenever a
|
||||
* post is made), vichan will add a random amount of hidden, obscure fields to it to
|
||||
* confuse bots and upset hackers. These fields and their respective obscure values are
|
||||
* validated upon posting with a 160-bit "hash". That hash can only be used as many times
|
||||
* as you specify; otherwise, flooding bots could just keep reusing the same hash.
|
||||
* Once a new set of inputs (and the hash) are generated, old hashes for the same thread
|
||||
* and board are set to expire. Because you have to reload the page to get the new set
|
||||
* of inputs and hash, if they expire too quickly and more than one person is viewing the
|
||||
* page at a given time, vichan would return false positives (depending on how long the
|
||||
* user sits on the page before posting). If your imageboard is quite fast/popular, set
|
||||
* $config['spam']['hidden_inputs_max_pass'] and $config['spam']['hidden_inputs_expire'] to
|
||||
* something higher to avoid false positives.
|
||||
*
|
||||
* See also: https://github.com/vichan-devel/vichan/wiki/your_request_looks_automated
|
||||
*
|
||||
*/
|
||||
|
||||
// Number of hidden fields to generate.
|
||||
$config['spam']['hidden_inputs_min'] = 4;
|
||||
$config['spam']['hidden_inputs_max'] = 12;
|
||||
|
||||
// How many times can a "hash" be used to post?
|
||||
$config['spam']['hidden_inputs_max_pass'] = 12;
|
||||
|
||||
// How soon after regeneration do hashes expire (in seconds)?
|
||||
$config['spam']['hidden_inputs_expire'] = 60 * 60 * 3; // three hours
|
||||
|
||||
// Whether to use Unicode characters in hidden input names and values.
|
||||
$config['spam']['unicode'] = true;
|
||||
|
||||
// These are fields used to confuse the bots. Make sure they aren't actually used by vichan, or it won't work.
|
||||
$config['spam']['hidden_input_names'] = array(
|
||||
'user',
|
||||
'username',
|
||||
'login',
|
||||
'search',
|
||||
'q',
|
||||
'url',
|
||||
'firstname',
|
||||
'lastname',
|
||||
'text',
|
||||
'message'
|
||||
);
|
||||
|
||||
// Always update this when adding new valid fields to the post form, or EVERYTHING WILL BE DETECTED AS SPAM!
|
||||
$config['spam']['valid_inputs'] = array(
|
||||
'hash',
|
||||
'board',
|
||||
'thread',
|
||||
'mod',
|
||||
'name',
|
||||
'email',
|
||||
'subject',
|
||||
'post',
|
||||
'body',
|
||||
'password',
|
||||
'sticky',
|
||||
'lock',
|
||||
'raw',
|
||||
'embed',
|
||||
'g-recaptcha-response',
|
||||
'h-captcha-response',
|
||||
'captcha_cookie',
|
||||
'captcha_text',
|
||||
'spoiler',
|
||||
'page',
|
||||
'file_url',
|
||||
'json_response',
|
||||
'user_flag',
|
||||
'no_country',
|
||||
'tag',
|
||||
'simple_spam'
|
||||
);
|
||||
|
||||
// Enable simple anti-spam measure. Requires the end-user to answer a question before making a post.
|
||||
// Works very well against uncustomized spam. Answers are case-insensitive.
|
||||
// $config['simple_spam'] = array (
|
||||
|
@ -391,12 +391,6 @@ function define_groups() {
|
||||
ksort($config['mod']['groups']);
|
||||
}
|
||||
|
||||
function create_antibot($board, $thread = null) {
|
||||
require_once dirname(__FILE__) . '/anti-bot.php';
|
||||
|
||||
return _create_antibot($board, $thread);
|
||||
}
|
||||
|
||||
function sprintf3($str, $vars, $delim = '%') {
|
||||
$replaces = array();
|
||||
foreach ($vars as $k => $v) {
|
||||
@ -1528,43 +1522,6 @@ function purge_old_antispam() {
|
||||
return $query->rowCount();
|
||||
}
|
||||
|
||||
function _create_antibot($board, $thread) {
|
||||
global $config, $purged_old_antispam;
|
||||
|
||||
$antibot = new AntiBot([$board, $thread]);
|
||||
|
||||
// Delete old expired antispam, skipping those with NULL expiration timestamps (infinite lifetime).
|
||||
if (!isset($purged_old_antispam) && $config['auto_maintenance']) {
|
||||
$purged_old_antispam = true;
|
||||
query('DELETE FROM ``antispam`` WHERE `expires` < UNIX_TIMESTAMP()') or error(db_error());
|
||||
}
|
||||
|
||||
// Keep the now invalid timestamps around for a bit to enable users to post if they're still on an old version of
|
||||
// the HTML page.
|
||||
// By virtue of existing, we know that we're making a new version of the page, and the user from now on may just reload.
|
||||
if ($thread) {
|
||||
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` = :thread AND `expires` IS NULL');
|
||||
} else {
|
||||
$query = prepare('UPDATE ``antispam`` SET `expires` = UNIX_TIMESTAMP() + :expires WHERE `board` = :board AND `thread` IS NULL AND `expires` IS NULL');
|
||||
}
|
||||
|
||||
$query->bindValue(':board', $board);
|
||||
if ($thread) {
|
||||
$query->bindValue(':thread', $thread);
|
||||
}
|
||||
$query->bindValue(':expires', $config['spam']['hidden_inputs_expire']);
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
// Insert an antispam with infinite life as the HTML page of a thread might last well beyond the expiry date.
|
||||
$query = prepare('INSERT INTO ``antispam`` VALUES (:board, :thread, :hash, UNIX_TIMESTAMP(), NULL, 0)');
|
||||
$query->bindValue(':board', $board);
|
||||
$query->bindValue(':thread', $thread);
|
||||
$query->bindValue(':hash', $antibot->hash());
|
||||
$query->execute() or error(db_error($query));
|
||||
|
||||
return $antibot;
|
||||
}
|
||||
|
||||
function checkSpam(array $extra_salt = array()) {
|
||||
global $config, $pdo;
|
||||
|
||||
@ -1632,7 +1589,6 @@ function buildIndex($global_api = "yes") {
|
||||
$catalog_api_action = generation_strategy('sb_api', array($board['uri']));
|
||||
|
||||
$pages = null;
|
||||
$antibot = null;
|
||||
|
||||
if ($config['api']['enabled']) {
|
||||
$api = new Api(
|
||||
@ -1684,21 +1640,12 @@ function buildIndex($global_api = "yes") {
|
||||
if ($wont_build_this_page) continue;
|
||||
}
|
||||
|
||||
if ($config['try_smarter']) {
|
||||
$antibot = create_antibot($board['uri'], 0 - $page);
|
||||
$content['current_page'] = $page;
|
||||
}
|
||||
elseif (!$antibot) {
|
||||
$antibot = create_antibot($board['uri']);
|
||||
}
|
||||
$antibot->reset();
|
||||
if (!$pages) {
|
||||
$pages = getPages();
|
||||
}
|
||||
$content['pages'] = $pages;
|
||||
$content['pages'][$page-1]['selected'] = true;
|
||||
$content['btn'] = getPageButtons($content['pages']);
|
||||
$content['antibot'] = $antibot;
|
||||
if ($mod) {
|
||||
$content['pm'] = create_pm_header();
|
||||
}
|
||||
@ -2282,7 +2229,6 @@ function buildThread($id, $return = false, $mod = false) {
|
||||
error($config['error']['nonexistant']);
|
||||
|
||||
$hasnoko50 = $thread->postCount() >= $config['noko50_min'];
|
||||
$antibot = $mod || $return ? false : create_antibot($board['uri'], $id);
|
||||
|
||||
$options = [
|
||||
'board' => $board,
|
||||
@ -2293,7 +2239,6 @@ function buildThread($id, $return = false, $mod = false) {
|
||||
'mod' => $mod,
|
||||
'hasnoko50' => $hasnoko50,
|
||||
'isnoko50' => false,
|
||||
'antibot' => $antibot,
|
||||
'boardlist' => createBoardlist($mod),
|
||||
'return' => ($mod ? '?' . $board['url'] . $config['file_index'] : $config['root'] . $board['dir'] . $config['file_index'])
|
||||
];
|
||||
@ -2330,20 +2275,17 @@ function buildThread($id, $return = false, $mod = false) {
|
||||
} elseif ($action == 'rebuild') {
|
||||
$noko50fn = $board['dir'] . $config['dir']['res'] . link_for($thread, true);
|
||||
if ($hasnoko50 || file_exists($noko50fn)) {
|
||||
buildThread50($id, $return, $mod, $thread, $antibot);
|
||||
buildThread50($id, $return, $mod, $thread);
|
||||
}
|
||||
|
||||
file_write($board['dir'] . $config['dir']['res'] . link_for($thread), $body);
|
||||
}
|
||||
}
|
||||
|
||||
function buildThread50($id, $return = false, $mod = false, $thread = null, $antibot = false) {
|
||||
function buildThread50($id, $return = false, $mod = false, $thread = null) {
|
||||
global $board, $config;
|
||||
$id = round($id);
|
||||
|
||||
if ($antibot)
|
||||
$antibot->reset();
|
||||
|
||||
if (!$thread) {
|
||||
$query = prepare(sprintf("SELECT * FROM ``posts_%s`` WHERE (`thread` IS NULL AND `id` = :id) OR `thread` = :id ORDER BY `thread`,`id` DESC LIMIT :limit", $board['uri']));
|
||||
$query->bindValue(':id', $id, PDO::PARAM_INT);
|
||||
@ -2405,7 +2347,6 @@ function buildThread50($id, $return = false, $mod = false, $thread = null, $anti
|
||||
'mod' => $mod,
|
||||
'hasnoko50' => $hasnoko50,
|
||||
'isnoko50' => true,
|
||||
'antibot' => $mod ? false : ($antibot ? $antibot : create_antibot($board['uri'], $id)),
|
||||
'boardlist' => createBoardlist($mod),
|
||||
'return' => ($mod ? '?' . $board['url'] . $config['file_index'] : $config['root'] . $board['dir'] . $config['file_index'])
|
||||
];
|
||||
|
@ -1,9 +1,6 @@
|
||||
<form name="post" onsubmit="return doPost(this);" enctype="multipart/form-data" action="{{ config.post_url }}" method="post">
|
||||
{{ antibot.html() }}
|
||||
{% if id %}<input type="hidden" name="thread" value="{{ id }}">{% endif %}
|
||||
{{ antibot.html() }}
|
||||
<input type="hidden" name="board" value="{{ board.uri }}">
|
||||
{{ antibot.html() }}
|
||||
{% if current_page %}
|
||||
<input type="hidden" name="page" value="{{ current_page }}">
|
||||
{% endif %}
|
||||
@ -12,11 +9,9 @@
|
||||
{% if not config.field_disable_name or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||
<th>
|
||||
{% trans %}Name{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="name" size="25" maxlength="35" autocomplete="off"> {% if config.allow_no_country and config.country_flags %}<input id="no_country" name="no_country" type="checkbox"> <label for="no_country">{% trans %}Don't show my flag{% endtrans %}</label>{% endif %}
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
{% if not config.field_disable_email or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||
@ -26,7 +21,6 @@
|
||||
{% else %}
|
||||
{% trans %}Email{% endtrans %}
|
||||
{% endif %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
{% if (mod and not post.mod|hasPermission(config.mod.bypass_field_disable, board.uri) and config.field_email_selectbox) or (not mod and config.field_email_selectbox) %}
|
||||
@ -39,17 +33,14 @@
|
||||
{% else %}
|
||||
<input type="text" name="email" size="25" maxlength="40" autocomplete="off">
|
||||
{% endif %}
|
||||
{{ antibot.html() }}
|
||||
{% if not (not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
<input accesskey="s" style="margin-left:2px;" type="submit" name="post" value="{% if id %}{{ config.button_reply }}{% else %}{{ config.button_newtopic }}{% endif %}" />{% if config.spoiler_images %} <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label> {% endif %}
|
||||
{% endif %}
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
{% if not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||
<th>
|
||||
{% trans %}Subject{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input style="float:left;" type="text" name="subject" size="25" maxlength="100" autocomplete="off">
|
||||
@ -60,11 +51,9 @@
|
||||
<tr>
|
||||
<th>
|
||||
{% trans %}Comment{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<textarea name="body" id="body" rows="5" cols="35"></textarea>
|
||||
{{ antibot.html() }}
|
||||
{% if not (not (config.field_disable_subject or (id and config.field_disable_reply_subject)) or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
{% if not (not config.field_disable_email or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri))) %}
|
||||
<input accesskey="s" style="margin-left:2px;" type="submit" name="post" value="{% if id %}{{ config.button_reply }}{% else %}{{ config.button_newtopic }}{% endif %}" />{% if config.spoiler_images %} <input id="spoiler" name="spoiler" type="checkbox"> <label for="spoiler">{% trans %}Spoiler Image{% endtrans %}</label>{% endif %}
|
||||
@ -80,11 +69,9 @@
|
||||
{% endif %}
|
||||
<th>
|
||||
{% trans %}Verification{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<div class="g-recaptcha" data-sitekey="{{ config.captcha.recaptcha.sitekey }}"></div>
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
@ -92,11 +79,9 @@
|
||||
<tr>
|
||||
<th>
|
||||
{% trans %}Verification{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<div class="h-captcha" data-sitekey="{{ config.captcha.hcaptcha.sitekey }}"></div>
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
@ -173,14 +158,12 @@
|
||||
<input style="display:inline" type="text" id="file_url" name="file_url" size="35">
|
||||
</div>
|
||||
{% endif %}
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>
|
||||
{% if config.enable_embedding %}
|
||||
<tr id="upload_embed">
|
||||
<th>
|
||||
{% trans %}Embed{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="embed" value="" size="30" maxlength="120" autocomplete="off">
|
||||
@ -211,27 +194,21 @@
|
||||
{% if not config.field_disable_password or (mod and post.mod|hasPermission(config.mod.bypass_field_disable, board.uri)) %}<tr>
|
||||
<th>
|
||||
{% trans %}Password{% endtrans %}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="password" value="" size="12" maxlength="18" autocomplete="off">
|
||||
<span class="unimportant">{% trans %}(For file deletion.){% endtrans %}</span>
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
{% if config.simple_spam and not id %}<tr>
|
||||
<th>
|
||||
{{ config.simple_spam.question }}
|
||||
{{ antibot.html() }}
|
||||
</th>
|
||||
<td>
|
||||
<input type="text" name="simple_spam" value="" size="12" maxlength="18" autocomplete="off">
|
||||
{{ antibot.html() }}
|
||||
</td>
|
||||
</tr>{% endif %}
|
||||
</table>
|
||||
{{ antibot.html(true) }}
|
||||
<input type="hidden" name="hash" value="{{ antibot.hash() }}">
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">{% verbatim %}
|
||||
|
Loading…
Reference in New Issue
Block a user