Conflicts:
	stylesheets/style.css
This commit is contained in:
8chan 2014-12-31 22:45:03 -08:00
commit 72255ad5b8
19 changed files with 180 additions and 68 deletions

View File

@ -26,9 +26,16 @@ if (count($files) == 0) {
$errorimage = $files[array_rand($files)];
}
if (preg_match('!'.$config['board_regex'].'/'.$config['dir']['res'].'\d+\.html!u', $_SERVER['REQUEST_URI'])) {
$return_link = '<a href="../index.html">[ Return ]</a>';
} else {
$return_link = '';
}
$page = <<<EOT
<div class="ban">
<p style="text-align:center"><img src="/static/404/{$errorimage}" style="width:100%"></p>
<p style="text-align:center"><a href="/index.html">[ Home ]</a>{$return_link}</p>
</div>
<script type="text/javascript">

View File

@ -130,7 +130,7 @@ if ($admin) {
unset($boards[$i]['img']);
}
array_splice($boards, 20);
array_splice($boards, 48);
$boards = array_values($boards);

View File

@ -398,6 +398,7 @@ FLAGS;
$auto_unicode = isset($_POST['auto_unicode']) ? 'true' : 'false';
$allow_roll = isset($_POST['allow_roll']) ? 'true' : 'false';
$image_reject_repost = isset($_POST['image_reject_repost']) ? 'true' : 'false';
$early_404 = isset($_POST['early_404']) ? 'true' : 'false';
$allow_delete = isset($_POST['allow_delete']) ? 'true' : 'false';
$allow_flash = isset($_POST['allow_flash']) ? '$config[\'allowed_ext_files\'][] = \'swf\';' : '';
$allow_pdf = isset($_POST['allow_pdf']) ? '$config[\'allowed_ext_files\'][] = \'pdf\';' : '';
@ -406,6 +407,7 @@ FLAGS;
$user_flags = isset($_POST['user_flags']) ? "if (file_exists('$b/flags.php')) { include 'flags.php'; }\n" : '';
$captcha = isset($_POST['captcha']) ? 'true' : 'false';
$force_subject_op = isset($_POST['force_subject_op']) ? 'true' : 'false';
$oekaki_js = <<<OEKAKI
@ -440,16 +442,30 @@ OEKAKI;
$replace = '';
if (isset($_POST['replace'])) {
if (sizeof($_POST['replace']) > 200 || sizeof($_POST['with']) > 200) {
error(_('Sorry, max 200 wordfilters allowed.'));
}
if (count($_POST['replace']) == count($_POST['with'])) {
foreach ($_POST['replace'] as $i => $r ) {
if ($r !== '') {
$w = $_POST['with'][$i];
if (strlen($w) > 255) {
error(sprintf(_('Sorry, %s is too long. Max replacement is 255 characters', utf8tohtml($w))));
}
$replace .= '$config[\'wordfilters\'][] = array(base64_decode(\'' . base64_encode($r) . '\'), base64_decode(\'' . base64_encode($w) . '\'));';
}
}
}
}
if (isset($_POST['hour_max_threads']) && in_array($_POST['hour_max_threads'], ['10', '25', '50', '100'])) {
$hour_max_threads = $_POST['hour_max_threads'];
} else {
$hour_max_threads = 'false';
}
if (!(strlen($title) < 40))
error('Invalid title');
if (!(strlen($subtitle) < 200))
@ -477,6 +493,7 @@ OEKAKI;
\$config['auto_unicode'] = $auto_unicode;
\$config['allow_roll'] = $allow_roll;
\$config['image_reject_repost'] = $image_reject_repost;
\$config['early_404'] = $early_404;
\$config['allow_delete'] = $allow_delete;
\$config['anonymous'] = base64_decode('$anonymous');
\$config['blotter'] = base64_decode('$blotter');
@ -484,6 +501,7 @@ OEKAKI;
\$config['default_stylesheet'] = array('Custom', \$config['stylesheets']['Custom']);
\$config['captcha']['enabled'] = $captcha;
\$config['force_subject_op'] = $force_subject_op;
\$config['hour_max_threads'] = $hour_max_threads;
$code_tags $katex $oekaki $replace $multiimage $allow_flash $allow_pdf $user_flags
if (\$config['disable_images'])
\$config['max_pages'] = 10000;
@ -529,6 +547,7 @@ EOT;
file_write($b.'/rules.txt', $_POST['rules']);
$_config = $config;
unset($config['wordfilters']);
// Faster than openBoard and bypasses cache...we're trusting the PHP output
// to be safe enough to run with every request, we can eval it here.
@ -560,10 +579,6 @@ EOT;
$rules = @file_get_contents($board['uri'] . '/rules.txt');
$css = @file_get_contents('stylesheets/board/' . $board['uri'] . '.css');
openBoard($b);
rebuildThemes('bans');
if ($config['cache']['enabled'])
cache::delete('board_' . $board['uri']);
cache::delete('all_boards');

View File

@ -236,13 +236,15 @@ class Bans {
}
static public function seen($ban_id) {
global $config;
$query = query("UPDATE ``bans`` SET `seen` = 1 WHERE `id` = " . (int)$ban_id) or error(db_error());
rebuildThemes('bans');
if (!$config['cron_bans']) rebuildThemes('bans');
}
static public function purge() {
global $config;
$query = query("DELETE FROM ``bans`` WHERE `expires` IS NOT NULL AND `expires` < " . time() . " AND `seen` = 1") or error(db_error());
rebuildThemes('bans');
if (!$config['cron_bans']) rebuildThemes('bans');
}
static public function delete($ban_id, $modlog = false, $boards = false, $dont_rebuild = false) {
@ -268,7 +270,7 @@ class Bans {
query("DELETE FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
if (!$dont_rebuild) rebuildThemes('bans');
if (!$dont_rebuild || !$config['cron_bans']) rebuildThemes('bans');
return true;
}
@ -350,7 +352,7 @@ class Bans {
' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
}
rebuildThemes('bans');
if (!$config['cron_bans']) rebuildThemes('bans');
return $pdo->lastInsertId();
}

View File

@ -780,6 +780,8 @@
$config['spoiler_image'] = 'static/spoiler.png';
// Location of thumbnail to use for deleted images.
// $config['image_deleted'] = 'static/deleted.png';
// Location of placeholder image for fileless posts in catalog.
$config['no_file_image'] = 'static/no-file.png';
// When a thumbnailed image is going to be the same (in dimension), just copy the entire file and use
// that as a thumbnail instead of resizing/redrawing.

View File

@ -149,7 +149,11 @@ function query($query) {
}
function db_error($PDOStatement = null) {
global $pdo, $db_error;
global $pdo, $db_error, $config;
if ($config['mask_db_error']) {
return _('The database returned an error while processing your request. Please try again later.');
}
if (isset($PDOStatement)) {
$db_error = $PDOStatement->errorInfo();

View File

@ -1158,11 +1158,26 @@ function clean() {
// I too wish there was an easier way of doing this...
$query = prepare(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset, 9001", $board['uri']));
$query->bindValue(':offset', $offset, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
deletePost($post['id'], false, false);
}
// Bump off threads with X replies earlier, spam prevention method
if ($config['early_404']) {
$offset = round($config['early_404_page']*$config['threads_per_page']);
$query = prepare(sprintf("SELECT `id` AS `thread_id`, (SELECT COUNT(`id`) FROM ``posts_%s`` WHERE `thread` = `thread_id`) AS `reply_count` FROM ``posts_%s`` WHERE `thread` IS NULL ORDER BY `sticky` DESC, `bump` DESC LIMIT :offset, 9001", $board['uri'], $board['uri']));
$query->bindValue(':offset', $offset, PDO::PARAM_INT);
$query->execute() or error(db_error($query));
while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
if ($post['reply_count'] < $config['early_404_replies']) {
deletePost($post['thread_id'], false, false);
}
}
}
}
function thread_find_page($thread) {

View File

@ -160,7 +160,6 @@
$config['footer'][] = 'All posts on 8chan.co are the responsibility of the individual poster and not the administration of 8chan.co, pursuant to 47 U.S.C. &sect; 230.';
$config['footer'][] = 'We have not been served any secret court orders and are not under any gag orders.';
$config['footer'][] = 'Contribute to 8chan.co development at <a href="https://github.com/ctrlcctrlv/8chan">github</a>';
$config['footer'][] = 'To make a DMCA request or report illegal content, please email <a href="mailto:admin@8chan.co">admin@8chan.co</a>.';
$config['search']['enable'] = true;
@ -169,6 +168,27 @@
$config['wordfilters'][] = array('\rule', ''); // 'true' means it's a regular expression
$config['hour_max_threads'] = false;
$config['filters'][] = array(
'condition' => array(
'custom' => function($post) {
global $config, $board;
if (!$config['hour_max_threads']) return false;
if ($post['op']) {
$query = prepare(sprintf('SELECT COUNT(*) AS `count` FROM ``posts_%s`` WHERE `thread` IS NULL AND FROM_UNIXTIME(`time`) > DATE_SUB(NOW(), INTERVAL 1 HOUR);', $board['uri']));
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']);
$query->execute() or error(db_error($query));
$r = $query->fetch(PDO::FETCH_ASSOC);
return ($r['count'] > $config['hour_max_threads']);
}
}
),
'action' => 'reject',
'message' => sprintf(_('On this board, to prevent raids only %d threads can be made per hour. Please try again later, or post in an existing thread.'), $config['hour_max_threads'])
);
$config['embedding'] = array(
array(
@ -202,6 +222,11 @@ $config['hash_masked_ip'] = true;
$config['force_subject_op'] = false;
$config['min_links'] = 0;
$config['min_body'] = 0;
$config['early_404'] = false;
$config['early_404_page'] = 5;
$config['early_404_replies'] = 10;
$config['cron_bans'] = true;
$config['mask_db_error'] = true;
// 8chan specific mod pages
require '8chan-mod-pages.php';

View File

@ -97,39 +97,6 @@ function modLog($action, $_board=null) {
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action);
}
// Validate session
if (isset($_COOKIE[$config['cookies']['mod']])) {
// Should be username:hash:salt
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
if (count($cookie) != 3) {
// Malformed cookies
destroyCookies();
mod_login();
exit;
}
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM ``mods`` WHERE `username` = :username");
$query->bindValue(':username', $cookie[0]);
$query->execute() or error(db_error($query));
$user = $query->fetch(PDO::FETCH_ASSOC);
// validate password hash
if ($cookie[1] !== mkhash($cookie[0], $user['password'], $cookie[2])) {
// Malformed cookies
destroyCookies();
mod_login();
exit;
}
$mod = array(
'id' => $user['id'],
'type' => $user['type'],
'username' => $cookie[0],
'boards' => explode(',', $user['boards'])
);
}
function create_pm_header() {
global $mod, $config;
@ -163,4 +130,50 @@ function make_secure_link_token($uri) {
return substr(sha1($config['cookies']['salt'] . '-' . $uri . '-' . $mod['id']), 0, 8);
}
function check_login($prompt = false) {
global $config, $mod;
// Validate session
if (isset($_COOKIE[$config['cookies']['mod']])) {
// Should be username:hash:salt
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]);
if (count($cookie) != 3) {
// Malformed cookies
destroyCookies();
if ($prompt) mod_login();
exit;
}
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM ``mods`` WHERE `username` = :username");
$query->bindValue(':username', $cookie[0]);
$query->execute() or error(db_error($query));
$user = $query->fetch(PDO::FETCH_ASSOC);
// validate password hash
if ($cookie[1] !== mkhash($cookie[0], $user['password'], $cookie[2])) {
// Malformed cookies
destroyCookies();
if ($prompt) mod_login();
exit;
}
$mod = array(
'id' => $user['id'],
'type' => $user['type'],
'username' => $cookie[0],
'boards' => explode(',', $user['boards'])
);
}
if ($config['debug'])
$parse_start_time = microtime(true);
// Fix for magic quotes
if (get_magic_quotes_gpc()) {
function strip_array($var) {
return is_array($var) ? array_map('strip_array', $var) : stripslashes($var);
}
$_GET = strip_array($_GET);
$_POST = strip_array($_POST);
}
}

View File

@ -15,6 +15,9 @@
var tab = Options.add_tab("general", "home", _("General"));
$(function(){
var help = $("<div><em>"+_("Note: Most option changes will only take effect on future page loads.")+"</em></div>");
help.appendTo(tab.content);
var stor = $("<div>"+_("Storage: ")+"</div>");
stor.appendTo(tab.content);

View File

@ -1,6 +1,27 @@
$(document).ready(function(){
window.boards = new Array();
if (window.Options && Options.get_tab('general')) {
Options.extend_tab("general", "<label id='show-top'><input type='checkbox' /> "+_('Show top boards')+"</label>");
if (typeof localStorage.show_top === 'undefined') {
localStorage.show_top = 'true';
var show_top = JSON.parse(localStorage.show_top);
$('#show-top>input').attr('checked', 'checked');
} else {
var show_top = JSON.parse(localStorage.show_top);
if (show_top) $('#show-top>input').attr('checked', 'checked');
}
$('#show-top>input').on('change', function() {
var show_top = ($(this).is(':checked'));
localStorage.show_top = JSON.stringify(show_top);
});
}
function handle_boards(data) {
$.each(data, function(k, v) {
if (v.uri != 'meta' && v.uri != 'b') {
@ -9,12 +30,12 @@ function handle_boards(data) {
})
if (boards[0]) {
$('.sub[data-description="2"]').after('<span class="sub" data-description="3"> [ '+boards.slice(0,15).join(" / ")+' ] </span>');
$('.sub[data-description="2"]').after('<span class="sub" data-description="3"> [ '+boards.slice(0,25).join(" / ")+' ] </span>');
}
}
$.getJSON("/boards-top20.json", handle_boards)
if (!(window.location.pathname != '' && window.location.pathname != '/' && window.location.pathname != '/index.html' && typeof show_top !== "undefined" && !show_top)) {
$.getJSON("/boards-top20.json", handle_boards)
}
});

13
mod.php
View File

@ -8,18 +8,7 @@ require 'inc/functions.php';
require 'inc/mod/pages.php';
require 'inc/mod/auth.php';
if ($config['debug'])
$parse_start_time = microtime(true);
// Fix for magic quotes
if (get_magic_quotes_gpc()) {
function strip_array($var) {
return is_array($var) ? array_map('strip_array', $var) : stripslashes($var);
}
$_GET = strip_array($_GET);
$_POST = strip_array($_POST);
}
check_login(true);
$query = isset($_SERVER['QUERY_STRING']) ? rawurldecode($_SERVER['QUERY_STRING']) : '';

View File

@ -218,6 +218,11 @@ elseif (isset($_POST['post'])) {
if (!openBoard($post['board']))
error($config['error']['noboard']);
checkDNSBL();
// Check if banned
checkBan($board['uri']);
// Check for CAPTCHA right after opening the board so the "return" link is in there
if ($config['recaptcha']) {
if (!isset($_POST['recaptcha_challenge_field']) || !isset($_POST['recaptcha_response_field']))
@ -257,13 +262,9 @@ elseif (isset($_POST['post'])) {
error($config['error']['referer']);
}
checkDNSBL();
// Check if banned
checkBan($board['uri']);
if ($post['mod'] = isset($_POST['mod']) && $_POST['mod']) {
require 'inc/mod/auth.php';
check_login(false);
if (!$mod) {
// Liar. You're not a mod.
error($config['error']['notamod']);

BIN
static/no-file.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -98,6 +98,7 @@ input[type="text"],input[type="password"],textarea {
text-transform: none;
word-spacing: normal;
max-width: 75%;
font-size: inherit;
}
#quick-reply input[type="text"], input[type="password"], #quick-reply textarea {
@ -858,7 +859,7 @@ pre {
#options_div {
width: 600px;
height: 320px;
height: 360px;
}
#alert_div {
@ -940,6 +941,10 @@ pre {
margin-top: 0px;
}
.mentioned {
word-wrap: break-word;
}
.poster_id {
cursor: pointer;
}

View File

@ -33,7 +33,6 @@
{% endif %}
<li><a href="?/noticeboard">{% trans 'View all noticeboard entries' %}</a></li>
{% endif %}
<li><a href="?/news">{% trans 'News' %}</a></li>
<li>
<a href="?/inbox">
{% trans 'PM inbox' %}

View File

@ -58,6 +58,13 @@
<tr><th>{% trans %}Max images per post{% endtrans %}</th><td><select name="max_images">{% for i in 1..5 %}<option value="{{ i }}" {% if config.max_images == i %} selected {% endif %}>{{ i }}</option>{% endfor %}</select></td></tr>
</table>
<table>
<tr><th colspan="2"><strong>{% trans %}Spam settings{% endtrans %}</strong></th></tr>
<tr><th>{% trans %}Early 404{% endtrans %}<br><span class="unimportant">With this enabled, threads with less than 10 replies will 404 at page 5 instead of at page 15.<br>In effect, this makes it so that raiders have to put 10 replies in all their threads to slide an entire board.</span></th><td><input type="checkbox" name="early_404" {% if config.early_404 %}checked{% endif %}></td></tr>
<tr><th>{% trans %}Max threads per hour board-wide{% endtrans %}<br><span class="unimportant">Only allow X threads to be made per hour, regardless of poster<br>If a thread is deleted, it's not counted</span></th><td><select name="hour_max_threads"><option value="none">none</option>{% for i in ['10', '25', '50', '100'] %}<option value="{{ i }}" {% if config.hour_max_threads == i %} selected {% endif %}>{{ i }}</option>{% endfor %}</select></td></tr>
</table>
<p style="text-align:center"><a href="?/banners/{{board.uri}}">{% trans %}Edit board banners{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/flags/{{board.uri}}">{% trans %}Edit board flags{% endtrans %}</a></p>
<p style="text-align:center"><a href="?/volunteers/{{board.uri}}">{% trans %}Edit board volunteers{% endtrans %}</a></p>

View File

@ -15,6 +15,7 @@
<h1>{{ settings.title }} (<a href="{{link}}">/{{ board }}/</a>)</h1>
<div class="subtitle">{{ settings.subtitle }}</div>
</header>
{{ config.ad.top }}
<span>{% trans 'Sort by' %}: </span>
<select id="sort_by" style="display: inline-block">

View File

@ -21,6 +21,7 @@
foreach ($boards as $board) {
$b = new Catalog();
$b->build($settings, $board);
if (php_sapi_name() === "cli") echo "Rebuilding $board catalog...\n";
}
} elseif ($action == 'post-thread' || ($settings['update_on_posts'] && $action == 'post') || ($settings['update_on_posts'] && $action == 'post-delete') && (in_array($board, $boards) | $settings['all'])) {
$b = new Catalog();
@ -77,6 +78,8 @@
$post['file'] = $config['uri_thumb'] . $files[0]->thumb;
}
}
} else {
$post['file'] = $config['root'] . $config['no_file_image'];
}
if (empty($post['image_count'])) $post['image_count'] = 0;