803 lines
28 KiB
PHP
803 lines
28 KiB
PHP
<?php
|
|
|
|
/*
|
|
* This is the endboard software, version beta 0.73
|
|
* It is a textboard written for the use in the darknets.
|
|
*
|
|
* Features are:
|
|
*
|
|
* -users can create their own subs
|
|
* -admin interface: delete single messages, ranges or whole subs
|
|
* -moderators interface: shadow single messages, ranges or whole subs
|
|
* -an api for automated posting
|
|
* -a simple spam check and doublepost protection
|
|
* -an api to export any sub to a json file
|
|
* -a bot trap and block for those following invisible links
|
|
* -a landing page
|
|
* -six diffent styles (css-files)
|
|
* -a simple BBCode dialect
|
|
*
|
|
* In contrast to earlier versions, this one relies on sqlite3 to save
|
|
* the messages and hashes for the captchas.
|
|
* Also, it respects the recent Linux conventions, so configfiles go to
|
|
* /etc/opt/endboard, workingfiles go to /var/opt/endboard and the
|
|
* actual webcontent goes to /srv/endboard.
|
|
* If you want custom paths, you'll need to change them in this file
|
|
* (index.php) as well as in config.php.
|
|
* However, the files "board.db" and "config.php" should not
|
|
* be in the webroot.
|
|
*
|
|
* The writing of this code started some time ago with another software
|
|
* called smolBBS. Although there is almost no original code left now,
|
|
* I still regard endboard as a fork of smolBBS.
|
|
* The author of smolBBS has required that the following text be
|
|
* distributed with any redistribution, so here it goes.
|
|
* The license and other conditions apply to endboard as well.
|
|
*
|
|
* IRC: *dulm @ irc.rizon.net
|
|
*
|
|
* Copyright (C) 2020 sandlind
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met:
|
|
*
|
|
* (1) Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* (2) Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* (3)The name of the author may not be used to
|
|
* endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
// This is at the top for your convenience (if you need to edit).
|
|
|
|
$config_file = '/etc/opt/endboard/config.php';
|
|
|
|
if ( file_exists($config_file) ) {
|
|
require_once $config_file;
|
|
// include the config file with the parameters and
|
|
// the landing page. No side effects.
|
|
$settings['config_file'] = $config_file;
|
|
} else {
|
|
echo "config file $config_file not found - exiting";
|
|
exit;
|
|
}
|
|
|
|
$db_file = $settings['work_dir'] . $settings['board_file'];
|
|
// initialize db
|
|
$db = new SQLite3($db_file, SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE);
|
|
$db->busyTimeout(50000);
|
|
// set a long timeout
|
|
|
|
// if this condition is fulfilled, we have most likely crashed before
|
|
// need to do real error handling (rewrite)
|
|
if ( (!file_exists($db_file)) ) {
|
|
echo "<h1>Cannot find file $db_file, are the settings correct ?</h1>";
|
|
exit;
|
|
}
|
|
|
|
require_once('/opt/endboard/admin.php');
|
|
// get the functions that the admin and mods need
|
|
require_once('/opt/endboard/base.php');
|
|
// get the basic functions used in most cases
|
|
require_once('/opt/endboard/bot.php');
|
|
// get the functions used to deal with bots
|
|
require_once('/opt/endboard/display.php');
|
|
// get the functions needed for display
|
|
require_once('/opt/endboard/post.php');
|
|
// get the functions needed to make posts
|
|
require_once('/opt/endboard/show.php');
|
|
// get the functions needed to show forms, subs and post history
|
|
|
|
make_tables($db);
|
|
//make tables if needed
|
|
|
|
// checks with which mode we are called
|
|
$short_mode = read_pretty_vars(1, 'alnum', 20);
|
|
// we read from the first position. Mode descriptions need 20 characters max.
|
|
|
|
// try to check the visitors (local) ip. On success, check if this ip should
|
|
// be blocked or not (according to the settings in the config file)
|
|
// also check if the portal has been passed or not, and display it
|
|
// if not (and it is enabled).
|
|
// Updated with more variables than just the (local) ip, it's now working
|
|
// surprisingly well, also on tor. The variable is still called 'ip'.
|
|
if ( (!empty($_SERVER['REMOTE_ADDR']))
|
|
&& ($settings['enable_logging'] == TRUE) ) {
|
|
$visitor_ip = $_SERVER['REMOTE_ADDR'];
|
|
|
|
$check_server = array (
|
|
'HTTP_USER_AGENT',
|
|
'HTTP_ACCEPT_ENCODING',
|
|
'HTTP_ACCEPT_LANGUAGE',
|
|
'HTTP_ACCEPT',
|
|
'HTTP_HOST',
|
|
'HTTP_X_REQUESTED_WITH',
|
|
'HTTP_X_I2P_DESTB64',
|
|
'HTTP_X_I2P_DESTB32',
|
|
'HTTP_X_I2P_DESTHASH',
|
|
'HTTP_UPGRADE_INSECURE_REQUESTS',
|
|
'HTTP_SEC_GPC',
|
|
'HTTP_PRIORITY',
|
|
'HTTP_SEC_FETCH_MODE',
|
|
'HTTP_SEC_FETCH_DEST'
|
|
);
|
|
|
|
foreach ($check_server as $id) {
|
|
if ( (!empty($_SERVER[$id])) ) {
|
|
$visitor_ip .= $_SERVER[$id];
|
|
}
|
|
}
|
|
|
|
$visitor_ip = hash('sha512', $visitor_ip);
|
|
|
|
if ( (empty($_POST['portal'])) && ($short_mode != 'b') ) {
|
|
check_portal($db, $settings, $visitor_ip);
|
|
} elseif ( (!empty($_POST['portal'])) ) {
|
|
$portal_message = 'pass';
|
|
log_event($db, $settings, 'portal', $portal_message, $visitor_ip);
|
|
redirect_target();
|
|
quit($db, '');
|
|
}
|
|
|
|
check_max_requests($db, $settings, $visitor_ip);
|
|
bot_block($db, $settings, $visitor_ip);
|
|
} else {
|
|
$visitor_ip = '';
|
|
}
|
|
|
|
$mode = set_mode($short_mode, $settings);
|
|
|
|
// initializes the css
|
|
$css = set_css($mode);
|
|
$css_file = set_css_file($css);
|
|
|
|
// First actions that are common to many modes: check which sub is
|
|
// requested and if it exists
|
|
$sub_wanted = array(
|
|
'admin', 'delete_admin', 'delete_mod', 'dump',
|
|
'mod', 'post', 'reply', 'view',
|
|
'edit'
|
|
);
|
|
|
|
if ( (in_array($mode, $sub_wanted)) ) {
|
|
$sub = set_sub($settings);
|
|
}
|
|
|
|
$check_sub = array(
|
|
'admin', 'delete_admin', 'delete_mod', 'dump',
|
|
'mod', 'reply', 'view', 'edit'
|
|
);
|
|
|
|
if ( (in_array($mode, $check_sub)) ) {
|
|
$sub_check = check_sub_exists($db, $sub);
|
|
|
|
if ($sub_check == FALSE) {
|
|
print_header($css_file);
|
|
quit($db, "<h1>Sub '$sub' does not exist.</h1>");
|
|
} else {
|
|
$sub = $sub_check;
|
|
}
|
|
}
|
|
|
|
// Do the things that only admins and mods need: check if access
|
|
// is enabled and do auth checks
|
|
$admin_mode = array(
|
|
'admin', 'change_mods', 'delete_admin', 'delete_logs',
|
|
'import', 'logs', 'shadow', 'unshadow_post',
|
|
'unshadow_sub', 'view_mods', 'dump_full'
|
|
);
|
|
|
|
if ( (in_array($mode, $admin_mode)) ) {
|
|
check_admin_panel($db, $settings);
|
|
$token = check_auth_admin($db, $settings);
|
|
}
|
|
|
|
$mod_mode = array(
|
|
'delete_mod', 'mod'
|
|
);
|
|
|
|
if ( (in_array($mode, $mod_mode)) ) {
|
|
check_mod_panel($db, $settings);
|
|
$token = check_auth_mod($db, $settings);
|
|
}
|
|
|
|
// Show the header, this is for almost all modes
|
|
$show_header = array(
|
|
'admin', 'apply', 'auth_admin', 'auth_mod',
|
|
'change_mods', 'delete_admin', 'delete_logs', 'delete_mod',
|
|
'destroy_token', 'import', 'individual_view', 'landing',
|
|
'logs', 'mod', 'password', 'post',
|
|
'reply', 'shadow', 'setup', 'subs',
|
|
'unshadow_post', 'unshadow_sub', 'view', 'view_mods',
|
|
'dump_full', 'edit', 'user'
|
|
);
|
|
|
|
if ( (in_array($mode, $show_header)) ) {
|
|
print_header($css_file);
|
|
}
|
|
|
|
// if debugging is enabled, dump info from $_SERVER to a file
|
|
if ( $settings['debug'] ) {
|
|
debug_server($db, $settings);
|
|
}
|
|
|
|
// Do particular actions for the mode we have been called with and exit.
|
|
// Note: there are no breaks in any of these cases, as there usually would.
|
|
// Instead, each case calls the quit function at some point, which exits
|
|
// the script.
|
|
switch($mode) {
|
|
|
|
// displays the admin panel
|
|
case 'admin':
|
|
echo "<h1>$sub</h1>";
|
|
show_subs_admin_mod($db, $settings, $css, $token, 'admin');
|
|
show_form_admin_mod($db, $sub, $token, 'admin');
|
|
print_sub($db, $sub, $css, $settings, 'all');
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// checks if applications are taken for moderator accounts, if yes,
|
|
// displays the form and processes the input
|
|
case 'apply':
|
|
if ($settings['take_applications'] != TRUE) {
|
|
header('HTTP/1.1 403 Forbidden');
|
|
quit($db, '403');
|
|
}
|
|
|
|
if (check_application_count($db) == TRUE) {
|
|
if ( (!empty($_POST['appl_name']))
|
|
&& (!empty($_POST['appl_email'])) ) {
|
|
if (strlen($_POST['appl_password']) < 10) {
|
|
// each password must be ten characters at least
|
|
$quit_message = '<h1>Password must be at least 10'
|
|
. ' characters. Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif (!preg_match("#[a-zA-Z]+#", $_POST['appl_password'])) {
|
|
$quit_message = '<h1>Password must include at least'
|
|
. ' one letter. Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif (preg_match('/^(.)\1*$/u ', $_POST['appl_password'])) {
|
|
$quit_message = '<h1>Password cannot be one letter '
|
|
. 'only. Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
}
|
|
|
|
$appl_name = filter($_POST['appl_name'], 'alnum', 50);
|
|
// 50 characters should be enough for a moderators name
|
|
$appl_email = filter($_POST['appl_email'], 'email', 50);
|
|
// 50 characters should be enough for a moderators email
|
|
$appl_password = password_hash($_POST['appl_password'],
|
|
PASSWORD_DEFAULT);
|
|
echo '<h1>Received application for moderator account: ';
|
|
echo "$appl_name.</h1>";
|
|
set_application($db, $appl_name, $appl_email,
|
|
$appl_password, $settings);
|
|
} else {
|
|
show_apply_form($db, $settings);
|
|
}
|
|
} else {
|
|
$quit_message = '<h1>Too many pending applications already,'
|
|
. ' try later.</h1>';
|
|
quit($db, $quit_message);
|
|
}
|
|
|
|
quit($db, "");
|
|
|
|
// authentification for the admin
|
|
case 'auth_admin':
|
|
check_admin_panel($db, $settings);
|
|
fail2ban($db, $settings);
|
|
if (!check_admin($db, $settings)) {
|
|
show_set_password_form($db, $settings);
|
|
} else {
|
|
show_auth_form($db, $css, $settings, 'admin');
|
|
}
|
|
quit($db, "");
|
|
|
|
// authentification for the mods
|
|
case 'auth_mod':
|
|
check_mod_panel($db, $settings);
|
|
fail2ban($db, $settings);
|
|
show_auth_form($db, $css, $settings, 'mod');
|
|
quit($db, "");
|
|
|
|
// checks if bot posting is enabled, if yes processes the post
|
|
case 'bot':
|
|
if ( (empty($settings['bot_keys']))
|
|
&& (empty($settings['anonymous_bot_subs'])) ) {
|
|
header( 'HTTP/1.1 403 Forbidden' );
|
|
quit($db, '403');
|
|
} elseif ( (post_block_bot($db, $settings, $visitor_ip) != TRUE) ) {
|
|
$bot_block_message = '429 - too many bot posts';
|
|
log_event($db, $settings, 'bot', $bot_block_message, $visitor_ip);
|
|
header( 'HTTP/1.1 429 Too Many Requests' );
|
|
quit($db, '429');
|
|
} else {
|
|
bot_me($db, $settings);
|
|
$bot_message = 'post attempt';
|
|
log_event($db, $settings, 'bot', $bot_message, $visitor_ip);
|
|
}
|
|
quit($db, '200');
|
|
|
|
// lets the admin view, disable and delete mod accounts
|
|
case 'change_mods':
|
|
if ( (isset($_POST['disable_mod']))
|
|
|| (isset($_POST['enable_mod']))
|
|
|| (isset($_POST['delete_mod'])) ) {
|
|
change_mods($db, $css, $settings, $token);
|
|
} else {
|
|
quit($db, '<h1>Nothing was selected, nothing was unshadowed.</h1>');
|
|
}
|
|
print_footer_admin($css, $settings, $token);
|
|
header( "refresh:3;url=/cm/8/$token" );
|
|
// 8 is the css of the admin.
|
|
// We wait 3 seconds with the redirection.
|
|
$quit_message = "<h1>Redirection in about 3 secs. If that does"
|
|
. " not work, go <a href='/cm/8/$token'>back</a>.";
|
|
quit($db, $quit_message);
|
|
|
|
// lets the admin delete messages or whole subs
|
|
case 'delete_admin':
|
|
|
|
if ( (!empty($_POST['delete_sub'])) ) {
|
|
|
|
if ( ($_POST['delete_sub'] != $sub) ) {
|
|
quit($db, "<h1>From here, you can only delete sub $sub.</h1>");
|
|
}
|
|
|
|
delete_sub($db, $sub, $settings, $token, 'no');
|
|
} elseif ( (!empty($_POST['delete_posts'])) ) {
|
|
delete_posts($db, $sub, $settings, $token, 'delete');
|
|
} else {
|
|
quit($db, '<h1>Nothing was selected, nothing was deleted.</h1>');
|
|
}
|
|
|
|
quit($db, "");
|
|
|
|
// lets the admin delete the endboard logs
|
|
case 'delete_logs':
|
|
$type = read_pretty_vars(2, 'alnum', 10);
|
|
// we read from the second position. 10
|
|
// characters is enough for the type.
|
|
|
|
show_subs_admin_mod($db, $settings, $css, $token, 'admin');
|
|
|
|
delete_logs($db, $type, $token);
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// lets moderators shadow messages or whole subs
|
|
case 'delete_mod':
|
|
|
|
if ( (!empty($_POST['shadow_sub'])) ) {
|
|
|
|
if ( $_POST['shadow_sub'] != $sub ) {
|
|
quit($db, "<h1>From here, you can only delete sub $sub.</h1>");
|
|
}
|
|
|
|
delete_sub($db, $sub, $settings, $token, 'yes');
|
|
} elseif ( (!empty($_POST['shadow_posts']))
|
|
&& (!empty($_POST['target_sub'])) ) {
|
|
delete_posts($db, $sub, $settings, $token, 'move');
|
|
} elseif ( (!empty($_POST['shadow_posts'])) ) {
|
|
delete_posts($db, $sub, $settings, $token, 'shadow');
|
|
} else {
|
|
quit($db, '<h1>Nothing was selected, nothing was deleted.</h1>');
|
|
}
|
|
|
|
quit($db, "");
|
|
|
|
// deletes an access token in the db, so it cannot be used anymore
|
|
case 'destroy_token':
|
|
$token = read_pretty_vars('last', 'alnum', 250);
|
|
// the length of the token is 250 characters
|
|
destroy_token($db, $token, $settings, 'log off');
|
|
header( 'refresh:3;url=/s/overboard' );
|
|
// wait 3 seconds with the redirection
|
|
$html_string = '<h1>You logged out. Redirection in about 3 secs.'
|
|
. ' If that does not work, go '
|
|
. '<a href=\'/s/overboard\'>back to overboard</a>.';
|
|
echo "$html_string";
|
|
quit($db, "");
|
|
|
|
// exports a thread, a sub or the whole board to a json file
|
|
// and sents it to the user
|
|
case 'dump':
|
|
$org_id = read_pretty_vars(3, 'number', 10);
|
|
// we read from the third postion, ten digits is enough
|
|
dump($db, $sub, $org_id, $settings);
|
|
quit($db, "");
|
|
|
|
// exports the full board to a json file, including tripcodes and
|
|
// shadowed posts, saves to working dir (only for admin)
|
|
case 'dump_full':
|
|
dump_full($db, $settings);
|
|
$quit_message = "<h1>All done.<a href=/a/main/$token>"
|
|
. " Back to admin panel</a></h1>";
|
|
quit($db, $quit_message);
|
|
|
|
// lets anybody see the edit history of one post. With the correct
|
|
// combination of name & tripkey, lets the user save a new edit of
|
|
// the post
|
|
case 'edit':
|
|
if ( ( $settings['enable_tripcodes'] != TRUE ) ) {
|
|
quit($db, "<h1>Tripcodes need to be enabled for this to work.</h1>");
|
|
}
|
|
|
|
if ( ( $settings['enable_edit'] != TRUE ) ) {
|
|
quit($db, "<h1>Editing is not enabled.</h1>");
|
|
}
|
|
|
|
fail2ban($db, $settings);
|
|
|
|
$post_id = read_pretty_vars(3, 'number', 10);
|
|
$org_id = reset_org_id($db, $sub, $post_id);
|
|
|
|
if (empty($_POST['edit_text'])) {
|
|
print_top_header("Edit post $sub/$post_id");
|
|
show_edit_form($db, $sub, $post_id, $visitor_ip, $css, $settings);
|
|
show_post_history($db, $sub, $post_id, $settings);
|
|
} else {
|
|
make_edit($db, $sub, $_POST['post_id'], $visitor_ip, $settings);
|
|
answer_redirect($sub, $css, '', $settings);
|
|
}
|
|
|
|
$msg = $sub . '/' . $post_id;
|
|
print_footer_reply($sub, '', $css, $msg, $org_id, $settings);
|
|
quit($db, '');
|
|
|
|
// lets the admin import json dumps
|
|
case 'import':
|
|
import_overboard($db, $settings);
|
|
$quit_message = "<h1>All done.<a href=/a/main/$token>"
|
|
. " Back to admin panel</a></h1>";
|
|
quit($db, $quit_message);
|
|
|
|
// shows an individual feed
|
|
case 'individual_view':
|
|
$ex_subs = array();
|
|
$in_subs = array();
|
|
$subs = read_pretty_vars(2, 'alnumplus', 1500);
|
|
// we read from the second position. 1500 characters
|
|
// should be enough to describe the subs (at least ~70 subs).
|
|
$title = '';
|
|
|
|
if (strpos($subs, '-') !== FALSE) {
|
|
$ex_subs = explode('-', $subs);
|
|
} elseif (strpos($subs, '+') !== FALSE) {
|
|
$in_subs = explode('+', $subs);
|
|
} elseif ( (!empty($_POST['ex_subs'])) ) {
|
|
$ex_subs = explode(' ', $_POST['ex_subs']);
|
|
} elseif ( (!empty($_POST['in_subs'])) ) {
|
|
$in_subs = explode(' ', $_POST['in_subs']);
|
|
} else {
|
|
quit($db, '<h1>Please choose subs to include or exclude.</h1>');
|
|
}
|
|
|
|
if (count($ex_subs) > 0) {
|
|
// if we have at least one exsub
|
|
foreach($ex_subs as $ex_sub) {
|
|
$ex_sub = filter($ex_sub, 'alnum', $settings['max_name_sub']);
|
|
|
|
if ( ($ex_sub != '')
|
|
&& (check_sub_exists($db, $ex_sub) == TRUE) ) {
|
|
$title .= "-" . $ex_sub;
|
|
}
|
|
|
|
}
|
|
|
|
$description = "ex";
|
|
} elseif (count($in_subs) > 0) {
|
|
// otherwise, if we have at least one insub
|
|
foreach($in_subs as $in_sub) {
|
|
$in_sub = filter($in_sub, 'alnum', $settings['max_name_sub']);
|
|
|
|
if ( ($in_sub != '')
|
|
&& (check_sub_exists($db, $in_sub) == TRUE) ) {
|
|
$title .= "+" . $in_sub;
|
|
}
|
|
|
|
}
|
|
|
|
$description = "inc";
|
|
}
|
|
|
|
if ( (empty($title)) ) {
|
|
$quit_message = '<h1>The subs you chose do not exist. Please '
|
|
. 'choose existing subs to include or exclude.</h1>';
|
|
quit($db, $quit_message);
|
|
}
|
|
|
|
echo "<title>$title</title>";
|
|
|
|
print_top_header("Multifeed ($description)");
|
|
echo '<p id="page">';
|
|
|
|
$total_posts = print_individual_feed($db, $css, $settings,
|
|
$ex_subs, $in_subs);
|
|
|
|
echo '</p>';
|
|
|
|
lay_trap($settings);
|
|
|
|
print_footer_multifeeds($title, $total_posts, $css, $settings);
|
|
quit($db, "");
|
|
|
|
// displays the landing page as defined in the config file
|
|
// also: check if there was a request URI, if yes, mark as bot
|
|
case 'landing':
|
|
if ( ( (!empty($_SERVER['REQUEST_URI'])) )
|
|
&& ( (strlen($_SERVER['REQUEST_URI']) > 6) ) ) {
|
|
// if more than 6 chars to go to the landing page,
|
|
// this could be a bot, especially if repeated
|
|
$bot_message = 'landing page bot request';
|
|
log_event($db, $settings, 'bot', $bot_message, $visitor_ip);
|
|
}
|
|
|
|
show_landing_page($css);
|
|
show_subs_no_count($db, $css, $settings);
|
|
lay_trap($settings);
|
|
print_footer_landing($db, $settings);
|
|
quit($db, "");
|
|
|
|
// lets the admin view the endboard logs
|
|
case 'logs':
|
|
show_subs_admin_mod($db, $settings, $css, $token, 'admin');
|
|
$type = read_pretty_vars(2, 'alnum', 10);
|
|
// we read from the second position
|
|
// 10 characters is enough
|
|
|
|
if ( (empty($type)) ) {
|
|
$type = 'all';
|
|
}
|
|
|
|
show_logs($db, $type, $token);
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// displays the mod panel
|
|
case 'mod':
|
|
echo "<h1>$sub</h1>";
|
|
show_subs_admin_mod($db, $settings, $css, $token, 'mod');
|
|
show_form_admin_mod($db, $sub, $token, 'mod');
|
|
print_sub($db, $sub, $css, $settings, 'all');
|
|
print_footer_mod($css, $settings, $token, $sub);
|
|
quit($db, "");
|
|
|
|
// shows the form to set passwords for the admin
|
|
case 'password':
|
|
check_admin_panel($db, $settings);
|
|
fail2ban($db, $settings);
|
|
|
|
if (check_admin($db, $settings)) {
|
|
show_auth_form($db, $css, $settings, 'admin');
|
|
} else {
|
|
show_set_password_form($db, $settings);
|
|
}
|
|
|
|
quit($db, "");
|
|
|
|
// makes a new post
|
|
case 'post':
|
|
$org_id = set_post_org_id();
|
|
$text = strip_tags($_POST['text']);
|
|
$text_id = hash('sha512', $text);
|
|
|
|
check_spam($db, $text, $settings);
|
|
|
|
if (check_free_space($db, $settings) == FALSE) {
|
|
$quit_message = '<h1>Filesystem is almost full, '
|
|
. 'no posting possible!</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif ( (check_original_content($db, $settings, $sub,
|
|
$text_id, $org_id) == FALSE) ) {
|
|
$quit_message = '<h1>This text has been posted before, '
|
|
. 'the admin requests original content.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif ( (mb_strtolower(substr( $sub, 0, 9 )) === 'overboard') ) {
|
|
// overboard has nine characters
|
|
$quit_message = '<h1>Subs cannot be named \'overboard\', also'
|
|
. ' their names cannot start with it.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif ( (mb_strtolower(substr( $sub, 0, 4 )) === 'main')
|
|
&& ($sub != 'main') ) {
|
|
// main has four characters
|
|
quit($db, '<h1>Subs names cannot start with \'main\'.</h1>');
|
|
} elseif ( (post_block_user($db, $settings, $visitor_ip) != TRUE) ) {
|
|
$post_block_message = '429 - too many user posts';
|
|
log_event($db, $settings, 'user', $post_block_message, $visitor_ip);
|
|
header( 'HTTP/1.1 429 Too Many Requests' );
|
|
quit($db, '429');
|
|
}
|
|
|
|
check_captcha($db, $settings);
|
|
|
|
$post_message = "post attempt";
|
|
log_event($db, $settings, 'user', $post_message, $visitor_ip);
|
|
|
|
$post_id = make_post($db, $sub, $settings, $text, $org_id);
|
|
answer_redirect($sub, $css, $post_id, $settings);
|
|
|
|
quit($db, "");
|
|
|
|
// shows a thread
|
|
case 'reply':
|
|
$org_id = set_org_id();
|
|
$link_to_reply = $org_id;
|
|
|
|
if ( (!check_post_exists($db, $sub, $org_id)) ) {
|
|
quit($db, "<h1>Post $org_id on sub $sub does not exist.</h1>");
|
|
} elseif ( (!check_org_id_exists($db, $sub, $org_id)) ) {
|
|
$org_id = reset_org_id($db, $sub, $org_id);
|
|
}
|
|
|
|
$quote = set_quote();
|
|
$msg = ($sub . '/' . $org_id);
|
|
|
|
print_top_header("$msg");
|
|
|
|
echo '<p id="page">';
|
|
|
|
show_post_form($db, $msg, $sub, $settings, $org_id,
|
|
$css, $quote, $visitor_ip);
|
|
print_thread($db, $sub, $css, $settings, $org_id, $link_to_reply);
|
|
lay_trap($settings);
|
|
print_footer_reply($sub, '', $css, $msg, $org_id, $settings);
|
|
|
|
quit($db, '');
|
|
|
|
// lets the admin set their password
|
|
case 'setup':
|
|
check_admin_panel($db, $settings);
|
|
|
|
if (check_admin($db, $settings)) {
|
|
show_auth_form($db, $css, $settings, 'admin');
|
|
}
|
|
|
|
if (strlen($_POST['auth_password']) < 10) {
|
|
// each password must have at least 10 characters
|
|
$quit_message = '<h1>Password must be at least 10 characters.'
|
|
. ' Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif (!preg_match("#[a-zA-Z]+#", $_POST['auth_password'])) {
|
|
$quit_message = '<h1>Password must include at least one letter.'
|
|
. ' Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
} elseif (preg_match('/^(.)\1*$/u ', $_POST['auth_password'])) {
|
|
$quit_message = '<h1>Password cannot be one letter only.'
|
|
. ' Please retry.</h1>';
|
|
quit($db, $quit_message);
|
|
}
|
|
|
|
$auth_name = filter($_POST['auth_name'], 'alnum', 50);
|
|
// 50 characters is enough for a admin name
|
|
$auth_password = password_hash($_POST['auth_password'],
|
|
PASSWORD_DEFAULT);
|
|
set_password($db, $auth_name, $auth_password,
|
|
$_POST['auth_token'], $settings);
|
|
$password_message = "password set for: $auth_name";
|
|
log_event($db, $settings, "sys", $password_message, $visitor_ip);
|
|
echo "<h1>$password_message</h1>";
|
|
echo '<h1><a href=\'/aa\'>Back to login</a></h1>';
|
|
quit($db, "");
|
|
|
|
// lets the admin view the shadowed posts and subs
|
|
case 'shadow':
|
|
show_shadowed($db, $css, $settings, $token);
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// displays all subs, including their message counts
|
|
case 'subs':
|
|
echo '<title>available subs</title>';
|
|
show_subs_count($db, $css, $settings);
|
|
show_set_feeds_form($db, $settings, $css);
|
|
lay_trap($settings);
|
|
quit($db, "");
|
|
|
|
// sends garbage links to nosy bots and spiders
|
|
case 'trap':
|
|
print_header('no_file');
|
|
trap_me($db, $settings, $visitor_ip);
|
|
quit($db, "");
|
|
|
|
// lets the admin unshadow a post that a moderator shadowed
|
|
case 'unshadow_post':
|
|
if ( (!empty($_POST['unshadow_id'])) ) {
|
|
unshadow_post($db, $settings, $token);
|
|
} else {
|
|
quit($db, '<h1>Nothing was selected, nothing was unshadowed.</h1>');
|
|
}
|
|
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// lets the admin unshadow a sub that a moderator shadowed
|
|
case 'unshadow_sub':
|
|
if ( (!empty($_POST['unshadow_sub'])) ) {
|
|
unshadow_sub($db, $settings, $token);
|
|
} else {
|
|
quit($db, '<h1>Nothing was selected, nothing was unshadowed.</h1>');
|
|
}
|
|
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
// shows all posts of one user
|
|
case 'user':
|
|
$ident = read_pretty_vars(2, 'alnumplus', 50);
|
|
$parts = explode('#', $ident);
|
|
$name = $parts[0];
|
|
echo "<title>$name</title>";
|
|
echo "<h1>Showing posts of user: $name</h1>";
|
|
print_user($db, $name, $css, $settings);
|
|
quit($db, "");
|
|
|
|
// shows a sub or the overboard
|
|
case 'view':
|
|
$page = set_page($mode);
|
|
|
|
if ( $sub == 'overboard' ) {
|
|
$title = $settings['title'];
|
|
} else {
|
|
$title = "sub/$sub";
|
|
}
|
|
|
|
echo "<title>$title</title>";
|
|
|
|
$total_posts = give_total_posts($db, $sub, TRUE, $settings);
|
|
|
|
if ( ($page != 'all')
|
|
&& ((($settings['pagination'] * $page) >
|
|
($total_posts + $settings['pagination']))) ) {
|
|
quit($db, "<h1>Not enough posts to display page = $page...!</h1>");
|
|
}
|
|
|
|
print_top_header("$sub");
|
|
echo '<p id="page">';
|
|
|
|
lay_trap($settings);
|
|
|
|
if ( ($sub != '') && $sub != 'overboard' ) {
|
|
show_post_form($db, '', $sub, $settings, '', $css, '', $visitor_ip);
|
|
print_sub($db, $sub, $css, $settings, $page);
|
|
} else {
|
|
print_overboard($db, $css, $settings, $page);
|
|
}
|
|
|
|
echo '</p>';
|
|
|
|
lay_trap($settings);
|
|
|
|
print_footer_sub($sub, $total_posts, $css, $page, $settings);
|
|
quit($db, "");
|
|
|
|
// lets the admin view, disable and delete mod accounts
|
|
case 'view_mods':
|
|
view_mods($db, $css, $settings, $token);
|
|
print_footer_admin($css, $settings, $token);
|
|
quit($db, "");
|
|
|
|
}
|
|
|
|
// EOF
|