@@ -277,10 +277,13 @@ function setupBoard($array) { | |||
$board = array( | |||
'uri' => $array['uri'], | |||
'name' => $array['title'], | |||
'title' => $array['subtitle'] | |||
'title' => $array['title'], | |||
'subtitle' => $array['subtitle'] | |||
); | |||
// older versions | |||
$board['name'] = &$board['title']; | |||
$board['dir'] = sprintf($config['board_path'], $board['uri']); | |||
$board['url'] = sprintf($config['board_abbreviation'], $board['uri']); | |||
@@ -64,7 +64,7 @@ function twig_date_filter($date, $format) { | |||
return strftime($format, $date); | |||
} | |||
function twig_hasPermission_filter($mod, $permission, $board) { | |||
function twig_hasPermission_filter($mod, $permission, $board = false) { | |||
return hasPermission($permission, $board, $mod); | |||
} | |||
@@ -0,0 +1,287 @@ | |||
<?php | |||
/* | |||
* Copyright (c) 2010-2012 Tinyboard Development Group | |||
*/ | |||
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { | |||
// You cannot request this file directly. | |||
exit; | |||
} | |||
// create a hash/salt pair for validate logins | |||
function mkhash($username, $password, $salt = false) { | |||
global $config; | |||
if (!$salt) { | |||
// create some sort of salt for the hash | |||
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15); | |||
$generated_salt = true; | |||
} | |||
// generate hash (method is not important as long as it's strong) | |||
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20); | |||
if (isset($generated_salt)) | |||
return Array($hash, $salt); | |||
else | |||
return $hash; | |||
} | |||
function login($username, $password, $makehash=true) { | |||
global $mod; | |||
// SHA1 password | |||
if ($makehash) { | |||
$password = sha1($password); | |||
} | |||
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1"); | |||
$query->bindValue(':username', $username); | |||
$query->bindValue(':password', $password); | |||
$query->execute() or error(db_error($query)); | |||
if ($user = $query->fetch()) { | |||
return $mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $username, | |||
'hash' => mkhash($username, $password), | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} else return false; | |||
} | |||
function setCookies() { | |||
global $mod, $config; | |||
if (!$mod) | |||
error('setCookies() was called for a non-moderator!'); | |||
setcookie($config['cookies']['mod'], | |||
$mod['username'] . // username | |||
':' . | |||
$mod['hash'][0] . // password | |||
':' . | |||
$mod['hash'][1], // salt | |||
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function destroyCookies() { | |||
global $config; | |||
// Delete the cookies | |||
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function create_pm_header() { | |||
global $mod; | |||
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1"); | |||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT); | |||
$query->execute() or error(db_error($query)); | |||
if ($pm = $query->fetch()) { | |||
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1); | |||
} | |||
return false; | |||
} | |||
function modLog($action, $_board=null) { | |||
global $mod, $board, $config; | |||
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)"); | |||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT); | |||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']); | |||
$query->bindValue(':time', time(), PDO::PARAM_INT); | |||
$query->bindValue(':text', $action); | |||
if (isset($_board)) | |||
$query->bindValue(':board', $_board); | |||
elseif (isset($board)) | |||
$query->bindValue(':board', $board['uri']); | |||
else | |||
$query->bindValue(':board', null, PDO::PARAM_NULL); | |||
$query->execute() or error(db_error($query)); | |||
if ($config['syslog']) | |||
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action); | |||
} | |||
// Generates a <ul> element with a list of linked | |||
// boards and their subtitles. (without the <ul> opening and ending tags) | |||
function ulBoards() { | |||
global $mod, $config; | |||
$body = ''; | |||
// List of boards | |||
$boards = listBoards(); | |||
foreach ($boards as &$b) { | |||
$body .= '<li>' . | |||
'<a href="?/' . | |||
sprintf($config['board_path'], $b['uri']) . $config['file_index'] . | |||
'">' . | |||
sprintf($config['board_abbreviation'], $b['uri']) . | |||
'</a> - ' . | |||
$b['title'] . | |||
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') . | |||
($mod['type'] >= $config['mod']['manageboards'] ? | |||
' <a href="?/' . $b['uri'] . '/edit" class="unimportant">[manage]</a>' : '') . | |||
'</li>'; | |||
} | |||
if ($mod['type'] >= $config['mod']['newboard']) { | |||
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>'; | |||
} | |||
return $body; | |||
} | |||
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) { | |||
global $config, $mod; | |||
$boards = listBoards(); | |||
$__boards = '<li><input type="radio" checked="checked" name="board" id="board_*" value=""/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>'; | |||
foreach ($boards as &$_board) { | |||
$__boards .= '<li>' . | |||
'<input type="radio" name="board" id="board_' . $_board['uri'] . '" value="' . $_board['uri'] . '">' . | |||
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' . | |||
($_board['uri'] == '*' ? | |||
'<em>"*"</em>' | |||
: | |||
sprintf($config['board_abbreviation'], $_board['uri']) | |||
) . | |||
' - ' . $_board['title'] . | |||
'</label>' . | |||
'</li>'; | |||
} | |||
return '<fieldset><legend>New ban</legend>' . | |||
'<form action="?/ban" method="post">' . | |||
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') . | |||
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') . | |||
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') . | |||
'<table>' . | |||
'<tr>' . | |||
'<th><label for="ip">IP ' . | |||
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') . | |||
'</span></label></th>' . | |||
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' . | |||
(isset($ip) ? | |||
'value="' . htmlentities($ip) . '" ' : '' | |||
) . | |||
'/></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="reason">Reason</label></th>' . | |||
'<td><textarea name="reason" id="reason" rows="5" cols="30">' . | |||
htmlentities($reason) . | |||
'</textarea></td>' . | |||
'</tr>' . | |||
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ? | |||
'<tr>' . | |||
'<th><label for="message">Message</label></th>' . | |||
'<td><input type="checkbox" id="public_message" name="public_message"/>' . | |||
' <input type="text" name="message" id="message" size="35" maxlength="200" value="' . htmlentities($config['mod']['default_ban_message']) . '" />' . | |||
' <span class="unimportant">(public; attached to post)</span></td>' . | |||
'<script type="text/javascript">' . | |||
'document.getElementById(\'message\').disabled = true;' . | |||
'document.getElementById(\'public_message\').onchange = function() {' . | |||
'document.getElementById(\'message\').disabled = !this.checked;' . | |||
'}' . | |||
'</script>' . | |||
'</tr>' | |||
: '') . | |||
'<tr>' . | |||
'<th><label for="length">Length</label></th>' . | |||
'<td><input type="text" name="length" id="length" size="20" maxlength="40" />' . | |||
' <span class="unimportant">(eg. "2d1h30m" or "2 days")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th>Board</th>' . | |||
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<td></td>' . | |||
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' . | |||
'</tr>' . | |||
'</table>' . | |||
'</form>' . | |||
'</fieldset>'; | |||
} | |||
function form_newBoard() { | |||
return '<fieldset><legend>New board</legend>' . | |||
'<form action="?/new" method="post">' . | |||
'<table>' . | |||
'<tr>' . | |||
'<th><label for="board">URI</label></th>' . | |||
'<td><input type="text" name="uri" id="board" size="10" />' . | |||
' <span class="unimportant">(eg. "b"; "mu")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="title">Title</label></th>' . | |||
'<td><input type="text" name="title" id="title" size="25" />' . | |||
' <span class="unimportant">(eg. "Random")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="subtitle">Subtitle</label></th>' . | |||
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' . | |||
' <span class="unimportant">(optional)</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<td></td>' . | |||
'<td><input name="new_board" type="submit" value="New Board" /></td>' . | |||
'</tr>' . | |||
'</table>' . | |||
'</form>' . | |||
'</fieldset>'; | |||
} | |||
function removeBan($id) { | |||
global $config, $memcached; | |||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id"); | |||
$query->bindValue(':id', $id, PDO::PARAM_INT); | |||
$query->execute() or error(db_error($query)); | |||
//if ($config['memcached']['enabled']) { | |||
// Remove cached ban | |||
// TODO | |||
// $memcached->delete("ban_{$id}"); | |||
//} | |||
} | |||
// Validate session | |||
if (isset($_COOKIE[$config['cookies']['mod']])) { | |||
// Should be username:hash:salt | |||
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]); | |||
if (count($cookie) != 3) { | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1"); | |||
$query->bindValue(':username', $cookie[0]); | |||
$query->execute() or error(db_error($query)); | |||
$user = $query->fetch(); | |||
// validate password hash | |||
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) { | |||
// Malformed cookies | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $cookie[0], | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} | |||
@@ -4,284 +4,12 @@ | |||
* Copyright (c) 2010-2012 Tinyboard Development Group | |||
*/ | |||
// WARNING: Including this file is DEPRECIATED. It's only here to support older versions and won't exist forever. | |||
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { | |||
// You cannot request this file directly. | |||
exit; | |||
} | |||
// create a hash/salt pair for validate logins | |||
function mkhash($username, $password, $salt = false) { | |||
global $config; | |||
if (!$salt) { | |||
// create some sort of salt for the hash | |||
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15); | |||
$generated_salt = true; | |||
} | |||
// generate hash (method is not important as long as it's strong) | |||
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20); | |||
if (isset($generated_salt)) | |||
return Array($hash, $salt); | |||
else | |||
return $hash; | |||
} | |||
function login($username, $password, $makehash=true) { | |||
global $mod; | |||
// SHA1 password | |||
if ($makehash) { | |||
$password = sha1($password); | |||
} | |||
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1"); | |||
$query->bindValue(':username', $username); | |||
$query->bindValue(':password', $password); | |||
$query->execute() or error(db_error($query)); | |||
if ($user = $query->fetch()) { | |||
return $mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $username, | |||
'hash' => mkhash($username, $password), | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} else return false; | |||
} | |||
function setCookies() { | |||
global $mod, $config; | |||
if (!$mod) | |||
error('setCookies() was called for a non-moderator!'); | |||
setcookie($config['cookies']['mod'], | |||
$mod['username'] . // username | |||
':' . | |||
$mod['hash'][0] . // password | |||
':' . | |||
$mod['hash'][1], // salt | |||
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function destroyCookies() { | |||
global $config; | |||
// Delete the cookies | |||
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function create_pm_header() { | |||
global $mod; | |||
$query = prepare("SELECT `id` FROM `pms` WHERE `to` = :id AND `unread` = 1"); | |||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT); | |||
$query->execute() or error(db_error($query)); | |||
if ($pm = $query->fetch()) { | |||
return Array('id' => $pm['id'], 'waiting' => $query->rowCount() - 1); | |||
} | |||
return false; | |||
} | |||
function modLog($action, $_board=null) { | |||
global $mod, $board, $config; | |||
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)"); | |||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT); | |||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']); | |||
$query->bindValue(':time', time(), PDO::PARAM_INT); | |||
$query->bindValue(':text', $action); | |||
if (isset($_board)) | |||
$query->bindValue(':board', $_board); | |||
elseif (isset($board)) | |||
$query->bindValue(':board', $board['uri']); | |||
else | |||
$query->bindValue(':board', null, PDO::PARAM_NULL); | |||
$query->execute() or error(db_error($query)); | |||
if ($config['syslog']) | |||
_syslog(LOG_INFO, '[mod/' . $mod['username'] . ']: ' . $action); | |||
} | |||
// Generates a <ul> element with a list of linked | |||
// boards and their subtitles. (without the <ul> opening and ending tags) | |||
function ulBoards() { | |||
global $mod, $config; | |||
$body = ''; | |||
// List of boards | |||
$boards = listBoards(); | |||
foreach ($boards as &$b) { | |||
$body .= '<li>' . | |||
'<a href="?/' . | |||
sprintf($config['board_path'], $b['uri']) . $config['file_index'] . | |||
'">' . | |||
sprintf($config['board_abbreviation'], $b['uri']) . | |||
'</a> - ' . | |||
$b['title'] . | |||
(isset($b['subtitle']) ? '<span class="unimportant"> — ' . $b['subtitle'] . '</span>' : '') . | |||
($mod['type'] >= $config['mod']['manageboards'] ? | |||
' <a href="?/' . $b['uri'] . '/edit" class="unimportant">[manage]</a>' : '') . | |||
'</li>'; | |||
} | |||
if ($mod['type'] >= $config['mod']['newboard']) { | |||
$body .= '<li style="margin-top:15px;"><a href="?/new"><strong>' . _('Create new board') . '</strong></a></li>'; | |||
} | |||
return $body; | |||
} | |||
function form_newBan($ip=null, $reason='', $continue=false, $delete=false, $board=false, $allow_public = false) { | |||
global $config, $mod; | |||
$boards = listBoards(); | |||
$__boards = '<li><input type="radio" checked="checked" name="board" id="board_*" value=""/> <label style="display:inline" for="board_*"><em>' . _('all boards') . '</em></label></li>'; | |||
foreach ($boards as &$_board) { | |||
$__boards .= '<li>' . | |||
'<input type="radio" name="board" id="board_' . $_board['uri'] . '" value="' . $_board['uri'] . '">' . | |||
'<label style="display:inline" for="board_' . $_board['uri'] . '"> ' . | |||
($_board['uri'] == '*' ? | |||
'<em>"*"</em>' | |||
: | |||
sprintf($config['board_abbreviation'], $_board['uri']) | |||
) . | |||
' - ' . $_board['title'] . | |||
'</label>' . | |||
'</li>'; | |||
} | |||
return '<fieldset><legend>New ban</legend>' . | |||
'<form action="?/ban" method="post">' . | |||
($continue ? '<input type="hidden" name="continue" value="' . htmlentities($continue) . '" />' : '') . | |||
($delete || $allow_public ? '<input type="hidden" name="' . (!$allow_public ? 'delete' : 'post') . '" value="' . htmlentities($delete) . '" />' : '') . | |||
($board ? '<input type="hidden" name="board" value="' . htmlentities($board) . '" />' : '') . | |||
'<table>' . | |||
'<tr>' . | |||
'<th><label for="ip">IP ' . | |||
($config['ban_cidr'] ? '<span class="unimportant">(or subnet)' : '') . | |||
'</span></label></th>' . | |||
'<td><input type="text" name="ip" id="ip" size="30" maxlength="30" ' . | |||
(isset($ip) ? | |||
'value="' . htmlentities($ip) . '" ' : '' | |||
) . | |||
'/></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="reason">Reason</label></th>' . | |||
'<td><textarea name="reason" id="reason" rows="5" cols="30">' . | |||
htmlentities($reason) . | |||
'</textarea></td>' . | |||
'</tr>' . | |||
($mod['type'] >= $config['mod']['public_ban'] && $allow_public ? | |||
'<tr>' . | |||
'<th><label for="message">Message</label></th>' . | |||
'<td><input type="checkbox" id="public_message" name="public_message"/>' . | |||
' <input type="text" name="message" id="message" size="35" maxlength="200" value="' . htmlentities($config['mod']['default_ban_message']) . '" />' . | |||
' <span class="unimportant">(public; attached to post)</span></td>' . | |||
'<script type="text/javascript">' . | |||
'document.getElementById(\'message\').disabled = true;' . | |||
'document.getElementById(\'public_message\').onchange = function() {' . | |||
'document.getElementById(\'message\').disabled = !this.checked;' . | |||
'}' . | |||
'</script>' . | |||
'</tr>' | |||
: '') . | |||
'<tr>' . | |||
'<th><label for="length">Length</label></th>' . | |||
'<td><input type="text" name="length" id="length" size="20" maxlength="40" />' . | |||
' <span class="unimportant">(eg. "2d1h30m" or "2 days")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th>Board</th>' . | |||
'<td><ul style="list-style:none;padding:2px 5px">' . $__boards . '</tl></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<td></td>' . | |||
'<td><input name="new_ban" type="submit" value="New Ban" /></td>' . | |||
'</tr>' . | |||
'</table>' . | |||
'</form>' . | |||
'</fieldset>'; | |||
} | |||
function form_newBoard() { | |||
return '<fieldset><legend>New board</legend>' . | |||
'<form action="?/new" method="post">' . | |||
'<table>' . | |||
'<tr>' . | |||
'<th><label for="board">URI</label></th>' . | |||
'<td><input type="text" name="uri" id="board" size="10" />' . | |||
' <span class="unimportant">(eg. "b"; "mu")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="title">Title</label></th>' . | |||
'<td><input type="text" name="title" id="title" size="25" />' . | |||
' <span class="unimportant">(eg. "Random")</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<th><label for="subtitle">Subtitle</label></th>' . | |||
'<td><input type="text" name="subtitle" id="subtitle" size="25" />' . | |||
' <span class="unimportant">(optional)</span></td>' . | |||
'</tr>' . | |||
'<tr>' . | |||
'<td></td>' . | |||
'<td><input name="new_board" type="submit" value="New Board" /></td>' . | |||
'</tr>' . | |||
'</table>' . | |||
'</form>' . | |||
'</fieldset>'; | |||
} | |||
function removeBan($id) { | |||
global $config, $memcached; | |||
$query = prepare("DELETE FROM `bans` WHERE `id` = :id"); | |||
$query->bindValue(':id', $id, PDO::PARAM_INT); | |||
$query->execute() or error(db_error($query)); | |||
//if ($config['memcached']['enabled']) { | |||
// Remove cached ban | |||
// TODO | |||
// $memcached->delete("ban_{$id}"); | |||
//} | |||
} | |||
// Validate session | |||
if (isset($_COOKIE[$config['cookies']['mod']])) { | |||
// Should be username:hash:salt | |||
$cookie = explode(':', $_COOKIE[$config['cookies']['mod']]); | |||
if (count($cookie) != 3) { | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1"); | |||
$query->bindValue(':username', $cookie[0]); | |||
$query->execute() or error(db_error($query)); | |||
$user = $query->fetch(); | |||
// validate password hash | |||
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) { | |||
// Malformed cookies | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $cookie[0], | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} | |||
require 'inc/mod/auth.php'; | |||
@@ -0,0 +1,124 @@ | |||
<?php | |||
/* | |||
* Copyright (c) 2010-2012 Tinyboard Development Group | |||
*/ | |||
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { | |||
// You cannot request this file directly. | |||
exit; | |||
} | |||
// create a hash/salt pair for validate logins | |||
function mkhash($username, $password, $salt = false) { | |||
global $config; | |||
if (!$salt) { | |||
// create some sort of salt for the hash | |||
$salt = substr(base64_encode(sha1(rand() . time(), true) . $config['cookies']['salt']), 0, 15); | |||
$generated_salt = true; | |||
} | |||
// generate hash (method is not important as long as it's strong) | |||
$hash = substr(base64_encode(md5($username . sha1($username . $password . $salt . ($config['mod']['lock_ip'] ? $_SERVER['REMOTE_ADDR'] : ''), true), true)), 0, 20); | |||
if (isset($generated_salt)) | |||
return Array($hash, $salt); | |||
else | |||
return $hash; | |||
} | |||
function login($username, $password, $makehash=true) { | |||
global $mod; | |||
// SHA1 password | |||
if ($makehash) { | |||
$password = sha1($password); | |||
} | |||
$query = prepare("SELECT `id`,`type`,`boards` FROM `mods` WHERE `username` = :username AND `password` = :password LIMIT 1"); | |||
$query->bindValue(':username', $username); | |||
$query->bindValue(':password', $password); | |||
$query->execute() or error(db_error($query)); | |||
if ($user = $query->fetch()) { | |||
return $mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $username, | |||
'hash' => mkhash($username, $password), | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} else return false; | |||
} | |||
function setCookies() { | |||
global $mod, $config; | |||
if (!$mod) | |||
error('setCookies() was called for a non-moderator!'); | |||
setcookie($config['cookies']['mod'], | |||
$mod['username'] . // username | |||
':' . | |||
$mod['hash'][0] . // password | |||
':' . | |||
$mod['hash'][1], // salt | |||
time() + $config['cookies']['expire'], $config['cookies']['jail'] ? $config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function destroyCookies() { | |||
global $config; | |||
// Delete the cookies | |||
setcookie($config['cookies']['mod'], 'deleted', time() - $config['cookies']['expire'], $config['cookies']['jail']?$config['cookies']['path'] : '/', null, false, true); | |||
} | |||
function modLog($action, $_board=null) { | |||
global $mod, $board, $config; | |||
$query = prepare("INSERT INTO `modlogs` VALUES (:id, :ip, :board, :time, :text)"); | |||
$query->bindValue(':id', $mod['id'], PDO::PARAM_INT); | |||
$query->bindValue(':ip', $_SERVER['REMOTE_ADDR']); | |||
$query->bindValue(':time', time(), PDO::PARAM_INT); | |||
$query->bindValue(':text', $action); | |||
if (isset($_board)) | |||
$query->bindValue(':board', $_board); | |||
elseif (isset($board)) | |||
$query->bindValue(':board', $board['uri']); | |||
else | |||
$query->bindValue(':board', null, PDO::PARAM_NULL); | |||
$query->execute() or error(db_error($query)); | |||
if ($config['syslog']) | |||
_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) { | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$query = prepare("SELECT `id`, `type`, `boards`, `password` FROM `mods` WHERE `username` = :username LIMIT 1"); | |||
$query->bindValue(':username', $cookie[0]); | |||
$query->execute() or error(db_error($query)); | |||
$user = $query->fetch(); | |||
// validate password hash | |||
if ($cookie[1] != mkhash($cookie[0], $user['password'], $cookie[2])) { | |||
// Malformed cookies | |||
destroyCookies(); | |||
error($config['error']['malformed']); | |||
} | |||
$mod = Array( | |||
'id' => $user['id'], | |||
'type' => $user['type'], | |||
'username' => $cookie[0], | |||
'boards' => explode(',', $user['boards']) | |||
); | |||
} | |||
@@ -0,0 +1,132 @@ | |||
<?php | |||
/* | |||
* Copyright (c) 2010-2012 Tinyboard Development Group | |||
*/ | |||
if (realpath($_SERVER['SCRIPT_FILENAME']) == str_replace('\\', '/', __FILE__)) { | |||
// You cannot request this file directly. | |||
exit; | |||
} | |||
function mod_page($title, $template, $args) { | |||
global $config, $mod; | |||
echo Element('page.html', array( | |||
'config' => $config, | |||
'mod' => $mod, | |||
'title' => $title, | |||
'body' => Element($template, | |||
array_merge( | |||
array('config' => $config, 'mod' => $mod), | |||
$args | |||
) | |||
) | |||
) | |||
); | |||
} | |||
function mod_login() { | |||
$args = array(); | |||
if (isset($_POST['login'])) { | |||
// Check if inputs are set and not empty | |||
if (!isset($_POST['username'], $_POST['password']) || $_POST['username'] == '' || $_POST['password'] == '') { | |||
$args['error'] = $config['error']['invalid']; | |||
} elseif (!login($_POST['username'], $_POST['password'])) { | |||
if ($config['syslog']) | |||
_syslog(LOG_WARNING, 'Unauthorized login attempt!'); | |||
$args['error'] = $config['error']['invalid']; | |||
} else { | |||
modLog("Logged in."); | |||
// Login successful | |||
// Set cookies | |||
setCookies(); | |||
header('Location: ?/', true, $config['redirect_http']); | |||
} | |||
} | |||
if (isset($_POST['username'])) | |||
$args['username'] = $_POST['username']; | |||
mod_page('Dashboard', 'mod/login.html', $args); | |||
} | |||
function mod_dashboard() { | |||
$args = array(); | |||
$args['boards'] = listBoards(); | |||
mod_page('Dashboard', 'mod/dashboard.html', $args); | |||
} | |||
function mod_view_board($boardName, $page_no = 1) { | |||
global $config, $mod; | |||
if (!openBoard($boardName)) | |||
error($config['error']['noboard']); | |||
if (!$page = index($page_no, $mod)) { | |||
error($config['error']['404']); | |||
} | |||
$page['pages'] = getPages(true); | |||
$page['pages'][$page_no-1]['selected'] = true; | |||
$page['btn'] = getPageButtons($page['pages'], true); | |||
$page['mod'] = true; | |||
$page['config'] = $config; | |||
echo Element('index.html', $page); | |||
} | |||
function mod_view_thread($boardName, $thread) { | |||
global $config, $mod; | |||
if (!openBoard($boardName)) | |||
error($config['error']['noboard']); | |||
$page = buildThread($thread, true, $mod); | |||
echo $page; | |||
} | |||
function mod_page_ip($ip) { | |||
global $config, $mod; | |||
$args = array(); | |||
$args['ip'] = $ip; | |||
$args['posts'] = array(); | |||
$boards = listBoards(); | |||
foreach ($boards as $board) { | |||
$query = prepare(sprintf('SELECT * FROM `posts_%s` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $board['uri'])); | |||
$query->bindValue(':ip', $ip); | |||
$query->bindValue(':limit', $config['mod']['ip_recentposts'], PDO::PARAM_INT); | |||
$query->execute() or error(db_error($query)); | |||
while ($post = $query->fetch()) { | |||
if (!$post['thread']) { | |||
$po = new Thread( | |||
$post['id'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], $post['body'], | |||
$post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], | |||
$post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['sticky'], $post['locked'], | |||
$post['sage'], $post['embed'], '?/', $mod, false | |||
); | |||
} else { | |||
$po = new Post( | |||
$post['id'], $post['thread'], $post['subject'], $post['email'], $post['name'], $post['trip'], $post['capcode'], | |||
$post['body'], $post['time'], $post['thumb'], $post['thumbwidth'], $post['thumbheight'], $post['file'], $post['filewidth'], | |||
$post['fileheight'], $post['filesize'], $post['filename'], $post['ip'], $post['embed'], '?/', $mod | |||
); | |||
} | |||
if (!isset($args['posts'][$board['uri']])) | |||
$args['posts'][$board['uri']] = array(); | |||
$args['posts'][$board['uri']][] = $po->build(true); | |||
} | |||
} | |||
mod_page("IP: $ip", 'mod/view_ip.html', $args); | |||
} | |||
@@ -35,10 +35,10 @@ | |||
{% if pm %}<div class="top_notice">You have <a href="?/PM/{{ pm.id }}">an unread PM</a>{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.</div><hr />{% endif %} | |||
{% if config.url_banner %}<img class="banner" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %} | |||
<header> | |||
<h1>{{ board.url }} - {{ board.name }}</h1> | |||
<h1>{{ board.url }} - {{ board.title }}</h1> | |||
<div class="subtitle"> | |||
{% if board.title %} | |||
{{ board.title }} | |||
{% if board.subtitle %} | |||
{{ board.subtitle }} | |||
{% endif %} | |||
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %} | |||
</div> | |||
@@ -1,27 +0,0 @@ | |||
{% if error %}<h2 style="text-align:center">{{ error }}</h2>{% endif %} | |||
<form action="" method="post"> | |||
{% if redirect %}<input type="hidden" name="redirect" value="{{ redirect }}" />{% endif %} | |||
<table style="margin-top:25px;"> | |||
<tr> | |||
<th> | |||
{% trans %}Username{% endtrans %} | |||
</th> | |||
<td> | |||
<input type="text" name="username" size="20" maxlength="30" value="{{ username }}"> | |||
</td> | |||
</tr> | |||
<tr> | |||
<th> | |||
{% trans %}Password{% endtrans %} | |||
</th> | |||
<td> | |||
<input type="password" name="password" size="20" maxlength="30" value=""> | |||
</td> | |||
</tr> | |||
<tr> | |||
<td></td> | |||
<td> | |||
<input type="submit" name="login" value="{% trans %}Continue{% endtrans %}" /> | |||
</td> | |||
</table> | |||
</form> |
@@ -36,10 +36,10 @@ | |||
{% if pm %}<div class="top_notice">You have <a href="?/PM/{{ pm.id }}">an unread PM</a>{% if pm.waiting > 0 %}, plus {{ pm.waiting }} more waiting{% endif %}.</div><hr />{% endif %} | |||
{% if config.url_banner %}<img class="banner" src="{{ config.url_banner }}" {% if config.banner_width or config.banner_height %}style="{% if config.banner_width %}width:{{ config.banner_width }}px{% endif %};{% if config.banner_width %}height:{{ config.banner_height }}px{% endif %}" {% endif %}alt="" />{% endif %} | |||
<header> | |||
<h1>{{ board.url }} - {{ board.name }}</h1> | |||
<h1>{{ board.url }} - {{ board.title }}</h1> | |||
<div class="subtitle"> | |||
{% if board.title %} | |||
{{ board.title }} | |||
{% if board.subtitle %} | |||
{{ board.subtitle }} | |||
{% endif %} | |||
{% if mod %}<p><a href="?/">{% trans %}Return to dashboard{% endtrans %}</a></p>{% endif %} | |||
</div> | |||