diff --git a/inc/8chan-functions.php b/inc/8chan-functions.php
index 5a50ec74..ef289616 100644
--- a/inc/8chan-functions.php
+++ b/inc/8chan-functions.php
@@ -54,3 +54,23 @@ function human_time_diff( $from, $to = '' ) {
return $since;
}
+
+function is_billion_laughs($arr1, $arr2) {
+ $arr = array();
+ foreach ($arr1 as $k => $v) {
+ $arr[$v] = $arr2[$k];
+ }
+
+ for ($i = 0; $i <= sizeof($arr); $i++) {
+ $cur = array_slice($arr, $i, 1);
+ $pst = array_slice($arr, 0, $i);
+ if (!$cur) continue;
+ $kk = array_keys($cur)[0];
+ $vv = array_values($cur)[0];
+ foreach ($pst as $k => $v) {
+ if (str_replace($kk, $vv, $v) != $v)
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/inc/8chan-mod-pages-functions.php b/inc/8chan-mod-pages-functions.php
new file mode 100644
index 00000000..eef96790
--- /dev/null
+++ b/inc/8chan-mod-pages-functions.php
@@ -0,0 +1,680 @@
+ 5)
+ error(_('Too many tags.'));
+
+ $delete = prepare('DELETE FROM ``board_tags`` WHERE uri = :uri');
+ $delete->bindValue(':uri', $b);
+ $delete->execute();
+
+ foreach ($_POST['tags'] as $i => $tag) {
+ if ($tag) {
+ if (strlen($tag) > 255)
+ continue;
+
+ $insert = prepare('INSERT INTO ``board_tags``(uri, tag) VALUES (:uri, :tag)');
+ $insert->bindValue(':uri', $b);
+ $insert->bindValue(':tag', utf8tohtml($tag));
+ $insert->execute();
+ }
+ }
+
+ $update = prepare('UPDATE ``boards`` SET sfw = :sfw WHERE uri = :uri');
+ $update->bindValue(':uri', $b);
+ $update->bindValue(':sfw', isset($_POST['sfw']));
+ $update->execute();
+ }
+ $query = prepare('SELECT * FROM ``board_tags`` WHERE uri = :uri');
+ $query->bindValue(':uri', $b);
+ $query->execute();
+
+ $tags = $query->fetchAll();
+
+ $query = prepare('SELECT `sfw` FROM ``boards`` WHERE uri = :uri');
+ $query->bindValue(':uri', $b);
+ $query->execute();
+
+ $sfw = $query->fetchColumn();
+
+ mod_page(_('Edit tags'), 'mod/tags.html', array('board'=>$board,'token'=>make_secure_link_token('tags/'.$board['uri']), 'tags'=>$tags, 'sfw'=>$sfw));
+ }
+
+ function mod_8_reassign($b) {
+ global $board, $config;
+
+ if (!openBoard($b))
+ error("Could not open board!");
+
+ if (!hasPermission($config['mod']['reassign_board'], $b))
+ error($config['error']['noaccess']);
+
+ $query = query("SELECT id, username FROM mods WHERE boards = '$b' AND type = 20");
+ $mods = $query->fetchAll();
+
+ if (!$mods) {
+ error('No mods?');
+ }
+
+ $password = base64_encode(openssl_random_pseudo_bytes(9));
+ $salt = generate_salt();
+ $hashed = hash('sha256', $salt . sha1($password));
+
+ $query = prepare('UPDATE ``mods`` SET `password` = :hashed, `salt` = :salt WHERE BINARY username = :mod');
+ $query->bindValue(':hashed', $hashed);
+ $query->bindValue(':salt', $salt);
+ $query->bindValue(':mod', $mods[0]['username']);
+ $query->execute();
+
+ $body = "Thanks for your interest in this board. Kindly find the username and password below. You can login at https://8ch.net/mod.php.
Username: {$mods[0]['username']}
Password: {$password}
Thanks for using 8chan!";
+
+ modLog("Reassigned board /$b/");
+
+ mod_page(_('Edit reassign'), 'blank.html', array('board'=>$board,'token'=>make_secure_link_token('reassign/'.$board['uri']),'body'=>$body));
+ }
+
+ function mod_8_volunteers($b) {
+ global $board, $config, $pdo;
+ if (!hasPermission($config['mod']['edit_volunteers'], $b))
+ error($config['error']['noaccess']);
+
+ if (!openBoard($b))
+ error("Could not open board!");
+
+ if (isset($_POST['username'], $_POST['password'])) {
+ $query = prepare('SELECT * FROM ``mods`` WHERE type = 19 AND boards = :board');
+ $query->bindValue(':board', $b);
+ $query->execute() or error(db_error($query));
+ $count = $query->rowCount();
+ $query = prepare('SELECT `username` FROM ``mods``');
+ $query->execute() or error(db_error($query));
+ $volunteers = $query->fetchAll(PDO::FETCH_ASSOC);
+
+ if ($_POST['username'] == '')
+ error(sprintf($config['error']['required'], 'username'));
+ if ($_POST['password'] == '')
+ error(sprintf($config['error']['required'], 'password'));
+ if (!preg_match('/^[a-zA-Z0-9._]{1,30}$/', $_POST['username']))
+ error(_('Invalid username'));
+
+ if ($count > 10) {
+ error(_('Too many board volunteers!'));
+ }
+
+ foreach ($volunteers as $i => $v) {
+ if (strtolower($_POST['username']) == strtolower($v['username'])) {
+ error(_('Refusing to create a volunteer with the same username as an existing one.'));
+ }
+ }
+
+ $salt = generate_salt();
+ $password = hash('sha256', $salt . sha1($_POST['password']));
+
+ $query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, 19, :board)');
+ $query->bindValue(':username', $_POST['username']);
+ $query->bindValue(':password', $password);
+ $query->bindValue(':salt', $salt);
+ $query->bindValue(':board', $b);
+ $query->execute() or error(db_error($query));
+
+ $userID = $pdo->lastInsertId();
+
+
+ modLog('Created a new volunteer: ' . utf8tohtml($_POST['username']) . ' (#' . $userID . ')');
+ }
+
+ if (isset($_POST['delete'])){
+ foreach ($_POST['delete'] as $i => $d){
+ $query = prepare('SELECT * FROM ``mods`` WHERE id = :id');
+ $query->bindValue(':id', $d);
+ $query->execute() or error(db_error($query));
+
+ $result = $query->fetch(PDO::FETCH_ASSOC);
+
+ if (!$result) {
+ error(_('Volunteer does not exist!'));
+ }
+
+ if ($result['boards'] != $b || $result['type'] != BOARDVOLUNTEER) {
+ error($config['error']['noaccess']);
+ }
+
+ $query = prepare('DELETE FROM ``mods`` WHERE id = :id');
+ $query->bindValue(':id', $d);
+ $query->execute() or error(db_error($query));
+ }
+ }
+
+ $query = prepare('SELECT * FROM ``mods`` WHERE type = 19 AND boards = :board');
+ $query->bindValue(':board', $b);
+ $query->execute() or error(db_error($query));
+ $volunteers = $query->fetchAll(PDO::FETCH_ASSOC);
+
+ mod_page(_('Edit volunteers'), 'mod/volunteers.html', array('board'=>$board,'token'=>make_secure_link_token('volunteers/'.$board['uri']),'volunteers'=>$volunteers));
+
+ }
+
+ function mod_8_flags($b) {
+ global $config, $mod, $board;
+ require_once 'inc/image.php';
+ if (!hasPermission($config['mod']['edit_flags'], $b))
+ error($config['error']['noaccess']);
+
+ if (!openBoard($b))
+ error("Could not open board!");
+
+ if (file_exists("$b/flags.ser"))
+ $config['user_flags'] = unserialize(file_get_contents("$b/flags.ser"));
+
+ $dir = 'static/custom-flags/'.$b;
+
+ if (!is_dir($dir)){
+ mkdir($dir, 0777, true);
+ }
+
+ function handle_file($id = false, $description, $b, $dir) {
+ global $config;
+
+ if (!isset($description) and $description)
+ error(_('You must enter a flag description!'));
+
+ if (strlen($description) > 255)
+ error(_('Flag description too long!'));
+
+ if ($id) {
+ $f = 'flag-'.$id;
+ } else {
+ $f = 'file';
+ $id = time() . substr(microtime(), 2, 3);
+ }
+
+ $upload = $_FILES[$f]['tmp_name'];
+ $banners = array_diff(scandir($dir), array('..', '.'));
+
+ if (!is_readable($upload))
+ error($config['error']['nomove']);
+
+ $extension = strtolower(mb_substr($_FILES[$f]['name'], mb_strrpos($_FILES[$f]['name'], '.') + 1));
+
+ if ($extension != 'png') {
+ error(_('Flags must be in PNG format.'));
+ }
+
+ if (filesize($upload) > 48000){
+ error(_('File too large!'));
+ }
+
+ if (!$size = @getimagesize($upload)) {
+ error($config['error']['invalidimg']);
+ }
+
+ if ($size[0] > 20 or $size[0] < 11 or $size[1] > 16 or $size[1] < 11){
+ error(_('Image wrong size!'));
+ }
+ if (sizeof($banners) > 256) {
+ error(_('Too many flags.'));
+ }
+
+ copy($upload, "$dir/$id.$extension");
+ purge("$dir/$id.$extension");
+ $config['user_flags'][$id] = utf8tohtml($description);
+ file_write($b.'/flags.ser', serialize($config['user_flags']));
+ }
+
+ // Handle a new flag, if any.
+ if (isset($_FILES['file'])){
+ handle_file(false, $_POST['description'], $b, $dir);
+ }
+
+ // Handle edits to existing flags.
+ foreach ($_FILES as $k => $a) {
+ if (empty($_FILES[$k]['tmp_name'])) continue;
+
+ if (preg_match('/^flag-(\d+)$/', $k, $matches)) {
+ $id = (int)$matches[1];
+ if (!isset($_POST['description-'.$id])) continue;
+
+ if (isset($config['user_flags'][$id])) {
+ handle_file($id, $_POST['description-'.$id], $b, $dir);
+ }
+ }
+ }
+
+ // Description just changed, flag not edited.
+ foreach ($_POST as $k => $v) {
+ if (!preg_match('/^description-(\d+)$/', $k, $matches)) continue;
+ $id = (int)$matches[1];
+ if (!isset($_POST['description-'.$id])) continue;
+
+ $description = $_POST['description-'.$id];
+
+ if (strlen($description) > 255)
+ error(_('Flag description too long!'));
+ $config['user_flags'][$id] = utf8tohtml($description);
+ file_write($b.'/flags.ser', serialize($config['user_flags']));
+ }
+
+ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+ $flags = << $d){
+ if (!preg_match('/[0-9+]/', $d)){
+ error('Nice try.');
+ }
+ unlink("$dir/$d.png");
+ $id = explode('.', $d)[0];
+ unset($config['user_flags'][$id]);
+ file_write($b.'/flags.ser', serialize($config['user_flags']));
+ }
+ }
+
+ if (isset($_POST['alphabetize'])) {
+ asort($config['user_flags'], SORT_NATURAL | SORT_FLAG_CASE);
+ file_write($b.'/flags.ser', serialize($config['user_flags']));
+ }
+
+ $banners = array_diff(scandir($dir), array('..', '.'));
+ mod_page(_('Edit flags'), 'mod/flags.html', array('board'=>$board,'banners'=>$banners,'token'=>make_secure_link_token('banners/'.$board['uri'])));
+ }
+
+ function mod_8_banners($b) {
+ global $config, $mod, $board;
+ require_once 'inc/image.php';
+
+ if (!hasPermission($config['mod']['edit_banners'], $b))
+ error($config['error']['noaccess']);
+
+ if (!openBoard($b))
+ error("Could not open board!");
+
+ $dir = 'static/banners/'.$b;
+
+ if (!is_dir($dir)){
+ mkdir($dir, 0777, true);
+ }
+
+
+ if (isset($_FILES['file'])){
+ $upload = $_FILES['file']['tmp_name'];
+ $banners = array_diff(scandir($dir), array('..', '.'));
+
+ if (!is_readable($upload))
+ error($config['error']['nomove']);
+
+ $id = time() . substr(microtime(), 2, 3);
+ $extension = strtolower(mb_substr($_FILES['file']['name'], mb_strrpos($_FILES['file']['name'], '.') + 1));
+
+ if (!in_array($extension, array('jpg','jpeg','png','gif'))){
+ error('Not an image extension.');
+ }
+
+ if (filesize($upload) > 512000){
+ error('File too large!');
+ }
+
+ if (!$size = @getimagesize($upload)) {
+ error($config['error']['invalidimg']);
+ }
+
+ if ($size[0] != 300 or $size[1] != 100){
+ error('Image wrong size!');
+ }
+ if (sizeof($banners) >= 50) {
+ error('Too many banners.');
+ }
+
+ copy($upload, "$dir/$id.$extension");
+ }
+
+ if (isset($_POST['delete'])){
+ foreach ($_POST['delete'] as $i => $d){
+ if (!preg_match('/[0-9+]\.(png|jpeg|jpg|gif)/', $d)){
+ error('Nice try.');
+ }
+ unlink("$dir/$d");
+ }
+ }
+
+ $banners = array_diff(scandir($dir), array('..', '.'));
+ mod_page(_('Edit banners'), 'mod/banners.html', array('board'=>$board,'banners'=>$banners,'token'=>make_secure_link_token('banners/'.$board['uri'])));
+
+ }
+
+ function mod_8_settings($b) {
+ global $config, $mod;
+
+ //if ($b === 'infinity' && $mod['type'] !== ADMIN)
+ // error('Settings temporarily disabled for this board.');
+
+ if (!in_array($b, $mod['boards']) and $mod['boards'][0] != '*')
+ error($config['error']['noaccess']);
+
+ if (!hasPermission($config['mod']['edit_settings'], $b))
+ error($config['error']['noaccess']);
+
+ if (!openBoard($b))
+ error("Could not open board!");
+
+ $possible_languages = array_diff(scandir('inc/locale/'), array('..', '.', '.tx', 'README.md'));
+
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $title = $_POST['title'];
+ $subtitle = $_POST['subtitle'];
+ $country_flags = isset($_POST['country_flags']) ? 'true' : 'false';
+ $field_disable_name = isset($_POST['field_disable_name']) ? 'true' : 'false';
+ $enable_embedding = isset($_POST['enable_embedding']) ? 'true' : 'false';
+ $force_image_op = isset($_POST['force_image_op']) ? 'true' : 'false';
+ $disable_images = isset($_POST['disable_images']) ? 'true' : 'false';
+ $poster_ids = isset($_POST['poster_ids']) ? 'true' : 'false';
+ $show_sages = isset($_POST['show_sages']) ? 'true' : 'false';
+ $auto_unicode = isset($_POST['auto_unicode']) ? 'true' : 'false';
+ $strip_combining_chars = isset($_POST['strip_combining_chars']) ? 'true' : 'false';
+ $allow_roll = isset($_POST['allow_roll']) ? 'true' : 'false';
+ $image_reject_repost = isset($_POST['image_reject_repost']) ? 'true' : 'false';
+ $image_reject_repost_in_thread = isset($_POST['image_reject_repost_in_thread']) ? '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\';' : '';
+ $code_tags = isset($_POST['code_tags']) ? '$config[\'additional_javascript\'][] = \'js/code_tags/run_prettify.js\';$config[\'markup\'][] = array("/\[code\](.+?)\[\/code\]/ms", "\$1
");' : '';
+ $katex = isset($_POST['katex']) ? '$config[\'katex\'] = true;$config[\'additional_javascript\'][] = \'js/katex/katex.min.js\'; $config[\'markup\'][] = array("/\[tex\](.+?)\[\/tex\]/ms", "\$1"); $config[\'additional_javascript\'][] = \'js/katex-enable.js\';' : '';
+ $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';
+ $force_flag = isset($_POST['force_flag']) ? 'true' : 'false';
+ $tor_posting = isset($_POST['tor_posting']) ? 'true' : 'false';
+ $new_thread_capt = isset($_POST['new_thread_capt']) ? 'true' : 'false';
+ $oekaki = isset($_POST['oekaki']) ? 'true' : 'false';
+
+ if ($_POST['locale'] !== 'en' && in_array($_POST['locale'], $possible_languages)) {
+ $locale = "\$config['locale'] = '{$_POST['locale']}.UTF-8';";
+ } else {
+ $locale = '';
+ }
+
+ if (isset($_POST['max_images']) && (int)$_POST['max_images'] && (int)$_POST['max_images'] <= 5) {
+ $_POST['max_images'] = (int)$_POST['max_images'];
+ $multiimage = "\$config['max_images'] = {$_POST['max_images']};
+ \$config['additional_javascript'][] = 'js/multi-image.js';";
+ } else {
+ $multiimage = '';
+ }
+
+ $anonymous = base64_encode($_POST['anonymous']);
+ $blotter = base64_encode(purify_html(html_entity_decode($_POST['blotter'])));
+ $add_to_config = @file_get_contents($b.'/extra_config.php');
+ $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 (is_billion_laughs($_POST['replace'], $_POST['with'])) {
+ error(_('Wordfilters may not wordfilter previous wordfilters. For example, if a filters to bb and b filters to cc, that is not allowed.'));
+ }
+ }
+
+ 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 (isset($_POST['max_pages'])) {
+ $mp = (int)$_POST['max_pages'];
+ if ($mp > 25 || $mp < 2) {
+ $max_pages = 15;
+ } else {
+ $max_pages = $mp;
+ }
+ } else {
+ $max_pages = 15;
+ }
+
+ if (isset($_POST['reply_limit'])) {
+ $rl = (int)$_POST['reply_limit'];
+ if ($rl > 750 || $rl < 250 || $rl % 25) {
+ $reply_limit = 250;
+ } else {
+ $reply_limit = $rl;
+ }
+ } else {
+ $reply_limit = 250;
+ }
+
+ if (isset($_POST['max_newlines'])) {
+ $mn = (int)$_POST['max_newlines'];
+ if ($mn < 20 || $mn > 300) {
+ $max_newlines = 0;
+ } else {
+ $max_newlines = $mn;
+ }
+ } else {
+ $max_newlines = $mn;
+ }
+
+ if (!(strlen($title) < 40))
+ error('Invalid title');
+ if (!(strlen($subtitle) < 200))
+ error('Invalid subtitle');
+
+ $query = prepare('UPDATE ``boards`` SET `title` = :title, `subtitle` = :subtitle, `indexed` = :indexed, `public_bans` = :public_bans, `public_logs` = :public_logs, `8archive` = :8archive WHERE `uri` = :uri');
+ $query->bindValue(':title', $title);
+ $query->bindValue(':subtitle', $subtitle);
+ $query->bindValue(':uri', $b);
+ $query->bindValue(':indexed', !isset($_POST['meta_noindex']));
+ $query->bindValue(':public_bans', isset($_POST['public_bans']));
+ $query->bindValue(':public_logs', (int)$_POST['public_logs']);
+ $query->bindValue(':8archive', isset($_POST['8archive']));
+ $query->execute() or error(db_error($query));
+
+ $config_file = <<fetchAll(PDO::FETCH_ASSOC)));
+ file_write($b.'/config.php', $config_file);
+ file_write('stylesheets/board/'.$b.'.css', $clean_css);
+
+ $_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.
+ eval(str_replace('flags.php', "$b/flags.php", preg_replace('/^\<\?php$/m', '', $config_file)));
+ // czaks: maybe reconsider using it, now that config is cached?
+
+ // Clean the cache
+ if ($config['cache']['enabled']) {
+ cache::delete('board_' . $board['uri']);
+ cache::delete('all_boards');
+
+ cache::delete('config_' . $board['uri']);
+ cache::delete('events_' . $board['uri']);
+
+ unlink('tmp/cache/locale_' . $board['uri']);
+ }
+
+ // be smarter about rebuilds...only some changes really require us to rebuild all threads
+ if ($_config['captcha']['enabled'] != $config['captcha']['enabled']
+ || $_config['new_thread_capt'] != $config['new_thread_capt'] /*New thread captcha - if toggling "enable captcha" requires this, toggling new thread capt does too, I guess.*/
+ || $_config['captcha']['extra'] != $config['captcha']['extra']
+ || $_config['blotter'] != $config['blotter']
+ || $_config['field_disable_name'] != $config['field_disable_name']
+ || $_config['show_sages'] != (isset($config['show_sages']) && $config['show_sages'])) {
+ buildIndex();
+ $query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $b)) or error(db_error());
+ while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
+ buildThread($post['id']);
+ }
+ }
+
+ modLog('Edited board settings', $b);
+ }
+
+ $query = prepare('SELECT * FROM boards WHERE uri = :board');
+ $query->bindValue(':board', $b);
+ $query->execute() or error(db_error($query));
+ $board = $query->fetchAll()[0];
+
+ $css = @file_get_contents('stylesheets/board/' . $board['uri'] . '.css');
+
+ mod_page(_('Board configuration'), 'mod/settings.html', array('board'=>$board, 'css'=>prettify_textarea($css), 'token'=>make_secure_link_token('settings/'.$board['uri']), 'languages'=>$possible_languages,'allowed_urls'=>$config['allowed_offsite_urls']));
+ }
diff --git a/inc/8chan-mod-pages.php b/inc/8chan-mod-pages.php
index 135a1c46..7894be58 100644
--- a/inc/8chan-mod-pages.php
+++ b/inc/8chan-mod-pages.php
@@ -1,26 +1,4 @@
$v) {
- $arr[$v] = $arr2[$k];
- }
-
- for ($i = 0; $i <= sizeof($arr); $i++) {
- $cur = array_slice($arr, $i, 1);
- $pst = array_slice($arr, 0, $i);
- if (!$cur) continue;
- $kk = array_keys($cur)[0];
- $vv = array_values($cur)[0];
- foreach ($pst as $k => $v) {
- if (str_replace($kk, $vv, $v) != $v)
- return true;
- }
- }
- return false;
- }
- }
-
$config['mod']['show_ip'] = GLOBALVOLUNTEER;
$config['mod']['show_ip_less'] = BOARDVOLUNTEER;
$config['mod']['manageusers'] = GLOBALVOLUNTEER;
@@ -67,636 +45,10 @@
$config['mod']['shadow_capcode'] = 'Global Volunteer';
- $config['mod']['custom_pages']['/tags/(\%b)'] = function ($b) {
- global $board, $config;
-
- if (!openBoard($b))
- error("Could not open board!");
-
- if (!hasPermission($config['mod']['edit_tags'], $b))
- error($config['error']['noaccess']);
-
- if (isset($_POST['tags'])) {
- if (sizeof($_POST['tags']) > 5)
- error(_('Too many tags.'));
-
- $delete = prepare('DELETE FROM ``board_tags`` WHERE uri = :uri');
- $delete->bindValue(':uri', $b);
- $delete->execute();
-
- foreach ($_POST['tags'] as $i => $tag) {
- if ($tag) {
- if (strlen($tag) > 255)
- continue;
-
- $insert = prepare('INSERT INTO ``board_tags``(uri, tag) VALUES (:uri, :tag)');
- $insert->bindValue(':uri', $b);
- $insert->bindValue(':tag', utf8tohtml($tag));
- $insert->execute();
- }
- }
-
- $update = prepare('UPDATE ``boards`` SET sfw = :sfw WHERE uri = :uri');
- $update->bindValue(':uri', $b);
- $update->bindValue(':sfw', isset($_POST['sfw']));
- $update->execute();
- }
- $query = prepare('SELECT * FROM ``board_tags`` WHERE uri = :uri');
- $query->bindValue(':uri', $b);
- $query->execute();
-
- $tags = $query->fetchAll();
-
- $query = prepare('SELECT `sfw` FROM ``boards`` WHERE uri = :uri');
- $query->bindValue(':uri', $b);
- $query->execute();
-
- $sfw = $query->fetchColumn();
-
- mod_page(_('Edit tags'), 'mod/tags.html', array('board'=>$board,'token'=>make_secure_link_token('tags/'.$board['uri']), 'tags'=>$tags, 'sfw'=>$sfw));
- };
-
- $config['mod']['custom_pages']['/reassign/(\%b)'] = function($b) {
- global $board, $config;
-
- if (!openBoard($b))
- error("Could not open board!");
-
- if (!hasPermission($config['mod']['reassign_board'], $b))
- error($config['error']['noaccess']);
-
- $query = query("SELECT id, username FROM mods WHERE boards = '$b' AND type = 20");
- $mods = $query->fetchAll();
-
- if (!$mods) {
- error('No mods?');
- }
-
- $password = base64_encode(openssl_random_pseudo_bytes(9));
- $salt = generate_salt();
- $hashed = hash('sha256', $salt . sha1($password));
-
- $query = prepare('UPDATE ``mods`` SET `password` = :hashed, `salt` = :salt WHERE BINARY username = :mod');
- $query->bindValue(':hashed', $hashed);
- $query->bindValue(':salt', $salt);
- $query->bindValue(':mod', $mods[0]['username']);
- $query->execute();
-
- $body = "Thanks for your interest in this board. Kindly find the username and password below. You can login at https://8ch.net/mod.php.
Username: {$mods[0]['username']}
Password: {$password}
Thanks for using 8chan!";
-
- modLog("Reassigned board /$b/");
-
- mod_page(_('Edit reassign'), 'blank.html', array('board'=>$board,'token'=>make_secure_link_token('reassign/'.$board['uri']),'body'=>$body));
- };
-
- $config['mod']['custom_pages']['/volunteers/(\%b)'] = function($b) {
- global $board, $config, $pdo;
- if (!hasPermission($config['mod']['edit_volunteers'], $b))
- error($config['error']['noaccess']);
-
- if (!openBoard($b))
- error("Could not open board!");
-
- if (isset($_POST['username'], $_POST['password'])) {
- $query = prepare('SELECT * FROM ``mods`` WHERE type = 19 AND boards = :board');
- $query->bindValue(':board', $b);
- $query->execute() or error(db_error($query));
- $count = $query->rowCount();
- $query = prepare('SELECT `username` FROM ``mods``');
- $query->execute() or error(db_error($query));
- $volunteers = $query->fetchAll(PDO::FETCH_ASSOC);
-
- if ($_POST['username'] == '')
- error(sprintf($config['error']['required'], 'username'));
- if ($_POST['password'] == '')
- error(sprintf($config['error']['required'], 'password'));
- if (!preg_match('/^[a-zA-Z0-9._]{1,30}$/', $_POST['username']))
- error(_('Invalid username'));
-
- if ($count > 10) {
- error(_('Too many board volunteers!'));
- }
-
- foreach ($volunteers as $i => $v) {
- if (strtolower($_POST['username']) == strtolower($v['username'])) {
- error(_('Refusing to create a volunteer with the same username as an existing one.'));
- }
- }
-
- $salt = generate_salt();
- $password = hash('sha256', $salt . sha1($_POST['password']));
-
- $query = prepare('INSERT INTO ``mods`` VALUES (NULL, :username, :password, :salt, 19, :board)');
- $query->bindValue(':username', $_POST['username']);
- $query->bindValue(':password', $password);
- $query->bindValue(':salt', $salt);
- $query->bindValue(':board', $b);
- $query->execute() or error(db_error($query));
-
- $userID = $pdo->lastInsertId();
-
-
- modLog('Created a new volunteer: ' . utf8tohtml($_POST['username']) . ' (#' . $userID . ')');
- }
-
- if (isset($_POST['delete'])){
- foreach ($_POST['delete'] as $i => $d){
- $query = prepare('SELECT * FROM ``mods`` WHERE id = :id');
- $query->bindValue(':id', $d);
- $query->execute() or error(db_error($query));
-
- $result = $query->fetch(PDO::FETCH_ASSOC);
-
- if (!$result) {
- error(_('Volunteer does not exist!'));
- }
-
- if ($result['boards'] != $b || $result['type'] != BOARDVOLUNTEER) {
- error($config['error']['noaccess']);
- }
-
- $query = prepare('DELETE FROM ``mods`` WHERE id = :id');
- $query->bindValue(':id', $d);
- $query->execute() or error(db_error($query));
- }
- }
-
- $query = prepare('SELECT * FROM ``mods`` WHERE type = 19 AND boards = :board');
- $query->bindValue(':board', $b);
- $query->execute() or error(db_error($query));
- $volunteers = $query->fetchAll(PDO::FETCH_ASSOC);
-
- mod_page(_('Edit volunteers'), 'mod/volunteers.html', array('board'=>$board,'token'=>make_secure_link_token('volunteers/'.$board['uri']),'volunteers'=>$volunteers));
-
- };
-
- $config['mod']['custom_pages']['/flags/(\%b)'] = function($b) {
- global $config, $mod, $board;
- require_once 'inc/image.php';
- if (!hasPermission($config['mod']['edit_flags'], $b))
- error($config['error']['noaccess']);
-
- if (!openBoard($b))
- error("Could not open board!");
-
- if (file_exists("$b/flags.ser"))
- $config['user_flags'] = unserialize(file_get_contents("$b/flags.ser"));
-
- $dir = 'static/custom-flags/'.$b;
-
- if (!is_dir($dir)){
- mkdir($dir, 0777, true);
- }
-
- function handle_file($id = false, $description, $b, $dir) {
- global $config;
-
- if (!isset($description) and $description)
- error(_('You must enter a flag description!'));
-
- if (strlen($description) > 255)
- error(_('Flag description too long!'));
-
- if ($id) {
- $f = 'flag-'.$id;
- } else {
- $f = 'file';
- $id = time() . substr(microtime(), 2, 3);
- }
-
- $upload = $_FILES[$f]['tmp_name'];
- $banners = array_diff(scandir($dir), array('..', '.'));
-
- if (!is_readable($upload))
- error($config['error']['nomove']);
-
- $extension = strtolower(mb_substr($_FILES[$f]['name'], mb_strrpos($_FILES[$f]['name'], '.') + 1));
-
- if ($extension != 'png') {
- error(_('Flags must be in PNG format.'));
- }
-
- if (filesize($upload) > 48000){
- error(_('File too large!'));
- }
-
- if (!$size = @getimagesize($upload)) {
- error($config['error']['invalidimg']);
- }
-
- if ($size[0] > 20 or $size[0] < 11 or $size[1] > 16 or $size[1] < 11){
- error(_('Image wrong size!'));
- }
- if (sizeof($banners) > 256) {
- error(_('Too many flags.'));
- }
-
- copy($upload, "$dir/$id.$extension");
- purge("$dir/$id.$extension");
- $config['user_flags'][$id] = utf8tohtml($description);
- file_write($b.'/flags.ser', serialize($config['user_flags']));
- }
-
- // Handle a new flag, if any.
- if (isset($_FILES['file'])){
- handle_file(false, $_POST['description'], $b, $dir);
- }
-
- // Handle edits to existing flags.
- foreach ($_FILES as $k => $a) {
- if (empty($_FILES[$k]['tmp_name'])) continue;
-
- if (preg_match('/^flag-(\d+)$/', $k, $matches)) {
- $id = (int)$matches[1];
- if (!isset($_POST['description-'.$id])) continue;
-
- if (isset($config['user_flags'][$id])) {
- handle_file($id, $_POST['description-'.$id], $b, $dir);
- }
- }
- }
-
- // Description just changed, flag not edited.
- foreach ($_POST as $k => $v) {
- if (!preg_match('/^description-(\d+)$/', $k, $matches)) continue;
- $id = (int)$matches[1];
- if (!isset($_POST['description-'.$id])) continue;
-
- $description = $_POST['description-'.$id];
-
- if (strlen($description) > 255)
- error(_('Flag description too long!'));
- $config['user_flags'][$id] = utf8tohtml($description);
- file_write($b.'/flags.ser', serialize($config['user_flags']));
- }
-
- if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- $flags = << $d){
- if (!preg_match('/[0-9+]/', $d)){
- error('Nice try.');
- }
- unlink("$dir/$d.png");
- $id = explode('.', $d)[0];
- unset($config['user_flags'][$id]);
- file_write($b.'/flags.ser', serialize($config['user_flags']));
- }
- }
-
- if (isset($_POST['alphabetize'])) {
- asort($config['user_flags'], SORT_NATURAL | SORT_FLAG_CASE);
- file_write($b.'/flags.ser', serialize($config['user_flags']));
- }
-
- $banners = array_diff(scandir($dir), array('..', '.'));
- mod_page(_('Edit flags'), 'mod/flags.html', array('board'=>$board,'banners'=>$banners,'token'=>make_secure_link_token('banners/'.$board['uri'])));
- };
-
- $config['mod']['custom_pages']['/banners/(\%b)'] = function($b) {
- global $config, $mod, $board;
- require_once 'inc/image.php';
-
- if (!hasPermission($config['mod']['edit_banners'], $b))
- error($config['error']['noaccess']);
-
- if (!openBoard($b))
- error("Could not open board!");
-
- $dir = 'static/banners/'.$b;
-
- if (!is_dir($dir)){
- mkdir($dir, 0777, true);
- }
-
-
- if (isset($_FILES['file'])){
- $upload = $_FILES['file']['tmp_name'];
- $banners = array_diff(scandir($dir), array('..', '.'));
-
- if (!is_readable($upload))
- error($config['error']['nomove']);
-
- $id = time() . substr(microtime(), 2, 3);
- $extension = strtolower(mb_substr($_FILES['file']['name'], mb_strrpos($_FILES['file']['name'], '.') + 1));
-
- if (!in_array($extension, array('jpg','jpeg','png','gif'))){
- error('Not an image extension.');
- }
-
- if (filesize($upload) > 512000){
- error('File too large!');
- }
-
- if (!$size = @getimagesize($upload)) {
- error($config['error']['invalidimg']);
- }
-
- if ($size[0] != 300 or $size[1] != 100){
- error('Image wrong size!');
- }
- if (sizeof($banners) >= 50) {
- error('Too many banners.');
- }
-
- copy($upload, "$dir/$id.$extension");
- }
-
- if (isset($_POST['delete'])){
- foreach ($_POST['delete'] as $i => $d){
- if (!preg_match('/[0-9+]\.(png|jpeg|jpg|gif)/', $d)){
- error('Nice try.');
- }
- unlink("$dir/$d");
- }
- }
-
- $banners = array_diff(scandir($dir), array('..', '.'));
- mod_page(_('Edit banners'), 'mod/banners.html', array('board'=>$board,'banners'=>$banners,'token'=>make_secure_link_token('banners/'.$board['uri'])));
-
- };
-
- $config['mod']['custom_pages']['/settings/(\%b)'] = function($b) {
- global $config, $mod;
-
- //if ($b === 'infinity' && $mod['type'] !== ADMIN)
- // error('Settings temporarily disabled for this board.');
-
- if (!in_array($b, $mod['boards']) and $mod['boards'][0] != '*')
- error($config['error']['noaccess']);
-
- if (!hasPermission($config['mod']['edit_settings'], $b))
- error($config['error']['noaccess']);
-
- if (!openBoard($b))
- error("Could not open board!");
-
- $possible_languages = array_diff(scandir('inc/locale/'), array('..', '.', '.tx', 'README.md'));
-
- if ($_SERVER['REQUEST_METHOD'] == 'POST') {
- $title = $_POST['title'];
- $subtitle = $_POST['subtitle'];
- $country_flags = isset($_POST['country_flags']) ? 'true' : 'false';
- $field_disable_name = isset($_POST['field_disable_name']) ? 'true' : 'false';
- $enable_embedding = isset($_POST['enable_embedding']) ? 'true' : 'false';
- $force_image_op = isset($_POST['force_image_op']) ? 'true' : 'false';
- $disable_images = isset($_POST['disable_images']) ? 'true' : 'false';
- $poster_ids = isset($_POST['poster_ids']) ? 'true' : 'false';
- $show_sages = isset($_POST['show_sages']) ? 'true' : 'false';
- $auto_unicode = isset($_POST['auto_unicode']) ? 'true' : 'false';
- $strip_combining_chars = isset($_POST['strip_combining_chars']) ? 'true' : 'false';
- $allow_roll = isset($_POST['allow_roll']) ? 'true' : 'false';
- $image_reject_repost = isset($_POST['image_reject_repost']) ? 'true' : 'false';
- $image_reject_repost_in_thread = isset($_POST['image_reject_repost_in_thread']) ? '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\';' : '';
- $code_tags = isset($_POST['code_tags']) ? '$config[\'additional_javascript\'][] = \'js/code_tags/run_prettify.js\';$config[\'markup\'][] = array("/\[code\](.+?)\[\/code\]/ms", "\$1
");' : '';
- $katex = isset($_POST['katex']) ? '$config[\'katex\'] = true;$config[\'additional_javascript\'][] = \'js/katex/katex.min.js\'; $config[\'markup\'][] = array("/\[tex\](.+?)\[\/tex\]/ms", "\$1"); $config[\'additional_javascript\'][] = \'js/katex-enable.js\';' : '';
- $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';
- $force_flag = isset($_POST['force_flag']) ? 'true' : 'false';
- $tor_posting = isset($_POST['tor_posting']) ? 'true' : 'false';
- $new_thread_capt = isset($_POST['new_thread_capt']) ? 'true' : 'false';
- $oekaki = isset($_POST['oekaki']) ? 'true' : 'false';
-
- if ($_POST['locale'] !== 'en' && in_array($_POST['locale'], $possible_languages)) {
- $locale = "\$config['locale'] = '{$_POST['locale']}.UTF-8';";
- } else {
- $locale = '';
- }
-
- if (isset($_POST['max_images']) && (int)$_POST['max_images'] && (int)$_POST['max_images'] <= 5) {
- $_POST['max_images'] = (int)$_POST['max_images'];
- $multiimage = "\$config['max_images'] = {$_POST['max_images']};
- \$config['additional_javascript'][] = 'js/multi-image.js';";
- } else {
- $multiimage = '';
- }
-
- $anonymous = base64_encode($_POST['anonymous']);
- $blotter = base64_encode(purify_html(html_entity_decode($_POST['blotter'])));
- $add_to_config = @file_get_contents($b.'/extra_config.php');
- $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 (is_billion_laughs($_POST['replace'], $_POST['with'])) {
- error(_('Wordfilters may not wordfilter previous wordfilters. For example, if a filters to bb and b filters to cc, that is not allowed.'));
- }
- }
-
- 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 (isset($_POST['max_pages'])) {
- $mp = (int)$_POST['max_pages'];
- if ($mp > 25 || $mp < 2) {
- $max_pages = 15;
- } else {
- $max_pages = $mp;
- }
- } else {
- $max_pages = 15;
- }
-
- if (isset($_POST['reply_limit'])) {
- $rl = (int)$_POST['reply_limit'];
- if ($rl > 750 || $rl < 250 || $rl % 25) {
- $reply_limit = 250;
- } else {
- $reply_limit = $rl;
- }
- } else {
- $reply_limit = 250;
- }
-
- if (isset($_POST['max_newlines'])) {
- $mn = (int)$_POST['max_newlines'];
- if ($mn < 20 || $mn > 300) {
- $max_newlines = 0;
- } else {
- $max_newlines = $mn;
- }
- } else {
- $max_newlines = $mn;
- }
-
- if (!(strlen($title) < 40))
- error('Invalid title');
- if (!(strlen($subtitle) < 200))
- error('Invalid subtitle');
-
- $query = prepare('UPDATE ``boards`` SET `title` = :title, `subtitle` = :subtitle, `indexed` = :indexed, `public_bans` = :public_bans, `public_logs` = :public_logs, `8archive` = :8archive WHERE `uri` = :uri');
- $query->bindValue(':title', $title);
- $query->bindValue(':subtitle', $subtitle);
- $query->bindValue(':uri', $b);
- $query->bindValue(':indexed', !isset($_POST['meta_noindex']));
- $query->bindValue(':public_bans', isset($_POST['public_bans']));
- $query->bindValue(':public_logs', (int)$_POST['public_logs']);
- $query->bindValue(':8archive', isset($_POST['8archive']));
- $query->execute() or error(db_error($query));
-
- $config_file = <<fetchAll(PDO::FETCH_ASSOC)));
- file_write($b.'/config.php', $config_file);
- file_write('stylesheets/board/'.$b.'.css', $clean_css);
-
- $_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.
- eval(str_replace('flags.php', "$b/flags.php", preg_replace('/^\<\?php$/m', '', $config_file)));
- // czaks: maybe reconsider using it, now that config is cached?
-
- // Clean the cache
- if ($config['cache']['enabled']) {
- cache::delete('board_' . $board['uri']);
- cache::delete('all_boards');
-
- cache::delete('config_' . $board['uri']);
- cache::delete('events_' . $board['uri']);
-
- unlink('tmp/cache/locale_' . $board['uri']);
- }
-
- // be smarter about rebuilds...only some changes really require us to rebuild all threads
- if ($_config['captcha']['enabled'] != $config['captcha']['enabled']
- || $_config['new_thread_capt'] != $config['new_thread_capt'] /*New thread captcha - if toggling "enable captcha" requires this, toggling new thread capt does too, I guess.*/
- || $_config['captcha']['extra'] != $config['captcha']['extra']
- || $_config['blotter'] != $config['blotter']
- || $_config['field_disable_name'] != $config['field_disable_name']
- || $_config['show_sages'] != (isset($config['show_sages']) && $config['show_sages'])) {
- buildIndex();
- $query = query(sprintf("SELECT `id` FROM ``posts_%s`` WHERE `thread` IS NULL", $b)) or error(db_error());
- while ($post = $query->fetch(PDO::FETCH_ASSOC)) {
- buildThread($post['id']);
- }
- }
-
- modLog('Edited board settings', $b);
- }
-
- $query = prepare('SELECT * FROM boards WHERE uri = :board');
- $query->bindValue(':board', $b);
- $query->execute() or error(db_error($query));
- $board = $query->fetchAll()[0];
-
- $css = @file_get_contents('stylesheets/board/' . $board['uri'] . '.css');
-
- mod_page(_('Board configuration'), 'mod/settings.html', array('board'=>$board, 'css'=>prettify_textarea($css), 'token'=>make_secure_link_token('settings/'.$board['uri']), 'languages'=>$possible_languages,'allowed_urls'=>$config['allowed_offsite_urls']));
- };
+ // Mod pages code now resides in 8chan-mod-pages-functions.php file
+ $config['mod']['custom_pages']['/tags/(\%b)'] = '8_tags';
+ $config['mod']['custom_pages']['/reassign/(\%b)'] = '8_reassign';
+ $config['mod']['custom_pages']['/volunteers/(\%b)'] = '8_volunteers';
+ $config['mod']['custom_pages']['/flags/(\%b)'] = '8_flags';
+ $config['mod']['custom_pages']['/banners/(\%b)'] = '8_banners';
+ $config['mod']['custom_pages']['/settings/(\%b)'] = '8_settings';
diff --git a/inc/instance-config.php b/inc/instance-config.php
index bc8d63da..152bb9d4 100644
--- a/inc/instance-config.php
+++ b/inc/instance-config.php
@@ -8,7 +8,7 @@
* You can copy values from config.php (defaults) and paste them here.
*/
require_once "lib/htmlpurifier-4.6.0/library/HTMLPurifier.auto.php";
- require_once "8chan-functions.php";
+ require_once "instance-functions.php";
// Note - you may want to change some of these in secrets.php instead of here
// See the secrets.example.php file
@@ -177,19 +177,7 @@
$config['hour_max_threads'] = 10;
$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']);
- }
- }
+ 'custom' => 'test_posts_per_hour'
),
'action' => 'reject',
'message' => 'On this board, to prevent raids the number of threads that can be created per hour is limited. Please try again later, or post in an existing thread.'
@@ -212,6 +200,7 @@ $config['enable_antibot'] = false;
$config['spam']['unicode'] = false;
$config['twig_cache'] = false;
$config['report_captcha'] = true;
+
// 8chan specific mod pages
require '8chan-mod-pages.php';
diff --git a/inc/instance-functions.php b/inc/instance-functions.php
new file mode 100644
index 00000000..f291714f
--- /dev/null
+++ b/inc/instance-functions.php
@@ -0,0 +1,17 @@
+ DATE_SUB(NOW(), INTERVAL 1 HOUR);', $board[$
+ $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']);
+ }
+}