From a9b7f9b1bc88b196a165ebb1bb74d01081d1e6fd Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Sat, 21 Sep 2013 12:51:23 +1000 Subject: begin implementation of in-built ban appealing --- inc/mod/pages.php | 110 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 63 insertions(+), 47 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 525a3d16..bae00a0f 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -197,37 +197,7 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { // Form a series of LIKE clauses for the query. // This gets a little complicated. - // Escape "escape" character - $query = str_replace('!', '!!', $query); - - // Escape SQL wildcard - $query = str_replace('%', '!%', $query); - - // Use asterisk as wildcard instead - $query = str_replace('*', '%', $query); - - $query = str_replace('`', '!`', $query); - - // Array of phrases to match - $match = array(); - - // Exact phrases ("like this") - if (preg_match_all('/"(.+?)"/', $query, $exact_phrases)) { - $exact_phrases = $exact_phrases[1]; - foreach ($exact_phrases as $phrase) { - $query = str_replace("\"{$phrase}\"", '', $query); - $match[] = $pdo->quote($phrase); - } - } - - // Non-exact phrases (ie. plain keywords) - $keywords = explode(' ', $query); - foreach ($keywords as $word) { - if (empty($word)) - continue; - $match[] = $pdo->quote($word); - } - + // Which `field` to search? if ($type == 'posts') $sql_field = array('body_nomarkup', 'filename', 'subject', 'filehash', 'ip', 'name', 'trip'); @@ -238,22 +208,6 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { if ($type == 'log') $sql_field = 'text'; - // Build the "LIKE 'this' AND LIKE 'that'" etc. part of the SQL query - $sql_like = ''; - foreach ($match as $phrase) { - if (!empty($sql_like)) - $sql_like .= ' AND '; - $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase); - if (is_array($sql_field)) { - foreach ($sql_field as $field) { - $sql_like .= '`' . $field . '` LIKE ' . $phrase . ' ESCAPE \'!\' OR'; - } - $sql_like = preg_replace('/ OR$/', '', $sql_like); - } else { - $sql_like .= '`' . $sql_field . '` LIKE ' . $phrase . ' ESCAPE \'!\''; - } - } - // Compile SQL query @@ -884,6 +838,68 @@ function mod_bans($page_no = 1) { mod_page(_('Ban list'), 'mod/ban_list.html', array('bans' => $bans, 'count' => Bans::count())); } +function mod_ban_appeals() { + global $config, $board; + + if (!hasPermission($config['mod']['view_ban_appeals'])) + error($config['error']['noaccess']); + + // Remove stale ban appeals + query("DELETE FROM ``ban_appeals`` WHERE NOT EXISTS (SELECT 1 FROM ``bans`` WHERE `ban_id` = ``bans``.`id`)") + or error(db_error()); + + if (isset($_POST['appeal_id']) && (isset($_POST['unban']) || isset($_POST['deny']))) { + if (!hasPermission($config['mod']['ban_appeals'])) + error($config['error']['noaccess']); + if (isset($_POST['unban'])) { + $query = query("SELECT `ban_id` FROM ``ban_appeals`` WHERE `id` = " . + (int)$_POST['appeal_id']) or error(db_error()); + if ($ban_id = $query->fetchColumn()) { + Bans::delete($ban_id); + query("DELETE FROM ``ban_appeals`` WHERE `id` = " . (int)$_POST['appeal_id']) or error(db_error()); + } + } else { + query("UPDATE ``ban_appeals`` SET `denied` = 1 WHERE `id` = " . (int)$_POST['appeal_id']) or error(db_error()); + } + + header('Location: ?/ban-appeals', true, $config['redirect_http']); + return; + } + + $query = query("SELECT *, ``ban_appeals``.`id` AS `id` FROM ``ban_appeals`` + LEFT JOIN ``bans`` ON `ban_id` = ``bans``.`id` + WHERE `denied` != 1 ORDER BY `time`") or error(db_error()); + $ban_appeals = $query->fetchAll(PDO::FETCH_ASSOC); + foreach ($ban_appeals as &$ban) { + if ($ban['post']) + $ban['post'] = json_decode($ban['post'], true); + $ban['mask'] = Bans::range_to_string(array($ban['ipstart'], $ban['ipend'])); + + if ($ban['post'] && isset($ban['post']['board'], $ban['post']['id'])) { + if (openBoard($ban['post']['board'])) { + $query = query(sprintf("SELECT `thumb`, `file` FROM ``posts_%s`` WHERE `id` = " . + (int)$ban['post']['id'], $board['uri'])); + if ($_post = $query->fetch(PDO::FETCH_ASSOC)) { + $ban['post'] = array_merge($ban['post'], $_post); + } else { + $ban['post']['file'] = 'deleted'; + $ban['post']['thumb'] = false; + } + } else { + $ban['post']['file'] = 'deleted'; + $ban['post']['thumb'] = false; + } + + if ($ban['post']['thread']) { + $ban['post'] = new Post($ban['post']); + } else { + $ban['post'] = new Thread($ban['post'], null, false, false); + } + } + } + + mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array('ban_appeals' => $ban_appeals)); +} function mod_lock($board, $unlock, $post) { global $config; -- cgit v1.3 From 39be89ba4945238f6311454283a66930b94577be Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Mon, 23 Sep 2013 10:11:16 +1000 Subject: ?/debug/apc --- inc/config.php | 2 ++ inc/mod/pages.php | 13 +++++++++++++ mod.php | 1 + templates/mod/debug/apc.html | 23 +++++++++++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 templates/mod/debug/apc.html (limited to 'inc/mod/pages.php') diff --git a/inc/config.php b/inc/config.php index 5105c25f..9ca4cfeb 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1340,6 +1340,8 @@ $config['mod']['news_delete'] = ADMIN; // Execute un-filtered SQL queries on the database (?/debug/sql) $config['mod']['debug_sql'] = DISABLED; + // Look through all cache values for debugging when APC is enabled (?/debug/apc) + $config['mod']['debug_apc'] = ADMIN; // Edit the current configuration (via web interface) $config['mod']['edit_config'] = ADMIN; // View ban appeals diff --git a/inc/mod/pages.php b/inc/mod/pages.php index bae00a0f..4346cf94 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -2354,3 +2354,16 @@ function mod_debug_sql() { mod_page(_('Debug: SQL'), 'mod/debug/sql.html', $args); } +function mod_debug_apc() { + global $config; + + if (!hasPermission($config['mod']['debug_apc'])) + error($config['error']['noaccess']); + + if ($config['cache']['enabled'] != 'apc') + error('APC is not enabled.'); + + $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/'); + + mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); +} diff --git a/mod.php b/mod.php index ca6d971e..cf6423ed 100644 --- a/mod.php +++ b/mod.php @@ -89,6 +89,7 @@ $pages = array( // these pages aren't listed in the dashboard without $config['debug'] '/debug/antispam' => 'debug_antispam', '/debug/recent' => 'debug_recent_posts', + '/debug/apc' => 'debug_apc', '/debug/sql' => 'secure_POST debug_sql', // This should always be at the end: diff --git a/templates/mod/debug/apc.html b/templates/mod/debug/apc.html new file mode 100644 index 00000000..53f59eb0 --- /dev/null +++ b/templates/mod/debug/apc.html @@ -0,0 +1,23 @@ + + + + + + + + + + {% for var in cached_vars %} + + + + + + + + + {% endfor %} +
KeyHitsCreatedExpiresSizeValue
{{ var.key }}{{ var.num_hits }}{{ var.creation_time|ago }} ago{{ (var.creation_time + var.ttl)|until }} (ttl: {{ var.ttl }}s){{ var.mem_size }} bytes + {% set value = var.value|json_encode %} + {{ value[:80]|e('html') }}{% if value|length > 80 %}…{% endif %} +
\ No newline at end of file -- cgit v1.3 From fcbc21131431725e4cb4cafde0fd907e9c607fa1 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Mon, 23 Sep 2013 10:21:18 +1000 Subject: Fixed weird bug with ?/debug/sql trying to allocate a few GB on some instances. Assuming bug with APCu. --- inc/mod/pages.php | 8 +++++++- templates/mod/debug/apc.html | 9 ++------- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 4346cf94..b240db55 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -2363,7 +2363,13 @@ function mod_debug_apc() { if ($config['cache']['enabled'] != 'apc') error('APC is not enabled.'); - $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/'); + $cache_info = apc_cache_info('user'); + // $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/'); + $cached_vars = array(); + foreach ($cache_info['cache_list'] as $var) { + $cached_vars[] = $var; + } + mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); } diff --git a/templates/mod/debug/apc.html b/templates/mod/debug/apc.html index 53f59eb0..0aa05e9f 100644 --- a/templates/mod/debug/apc.html +++ b/templates/mod/debug/apc.html @@ -5,19 +5,14 @@ Created Expires Size - Value {% for var in cached_vars %} - {{ var.key }} + {% if var.key %}{{ var.key }}{% else %}{{ var.info }}{% endif %} {{ var.num_hits }} {{ var.creation_time|ago }} ago - {{ (var.creation_time + var.ttl)|until }} (ttl: {{ var.ttl }}s) + {{ (var.creation_time + var.ttl)|until }} (ttl: {{ (time() + var.ttl)|until }}) {{ var.mem_size }} bytes - - {% set value = var.value|json_encode %} - {{ value[:80]|e('html') }}{% if value|length > 80 %}…{% endif %} - {% endfor %} \ No newline at end of file -- cgit v1.3 From d234c014f06955974e10a25b1199f22c226e7808 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Mon, 23 Sep 2013 10:41:47 +1000 Subject: ?/debug/apc with cache prefixes --- inc/mod/pages.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index b240db55..e47289b4 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -2368,8 +2368,10 @@ function mod_debug_apc() { // $cached_vars = new APCIterator('user', '/^' . $config['cache']['prefix'] . '/'); $cached_vars = array(); foreach ($cache_info['cache_list'] as $var) { + if ($config['cache']['prefix'] != '' && strpos(isset($var['key']) ? $var['key'] : $var['info'], $config['cache']['prefix']) !== 0) + continue; $cached_vars[] = $var; } - + mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); } -- cgit v1.3 From c8062fbf767100a46e32a81ed34d8d8eaf5c45e7 Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Mon, 23 Sep 2013 16:48:56 +1000 Subject: CSRF more mod pages --- inc/mod/pages.php | 124 +++++++++++++++++++++++++++-------- mod.php | 86 ++++++++++++------------ templates/mod/ban_appeals.html | 1 + templates/mod/ban_list.html | 3 +- templates/mod/board.html | 1 + templates/mod/config-editor-php.html | 1 + templates/mod/config-editor.html | 1 + templates/mod/dashboard.html | 2 +- templates/mod/new_pm.html | 1 + templates/mod/news.html | 3 +- templates/mod/noticeboard.html | 5 +- templates/mod/rebuild.html | 1 + templates/mod/report.html | 4 +- templates/mod/theme_config.html | 1 + templates/mod/themes.html | 4 +- templates/mod/user.html | 1 + templates/mod/users.html | 4 +- templates/mod/view_ip.html | 2 + 18 files changed, 166 insertions(+), 79 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index e47289b4..58cd5c26 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -156,7 +156,9 @@ function mod_dashboard() { if ($latest) $args['newer_release'] = $latest; } - + + $args['logout_token'] = make_secure_link_token('logout'); + mod_page(_('Dashboard'), 'mod/dashboard.html', $args); } @@ -389,7 +391,10 @@ function mod_edit_board($boardName) { header('Location: ?/', true, $config['redirect_http']); } else { - mod_page(sprintf('%s: ' . $config['board_abbreviation'], _('Edit board'), $board['uri']), 'mod/board.html', array('board' => $board)); + mod_page(sprintf('%s: ' . $config['board_abbreviation'], _('Edit board'), $board['uri']), 'mod/board.html', array( + 'board' => $board, + 'token' => make_secure_link_token('edit/' . $board['uri']) + )); } } @@ -459,7 +464,7 @@ function mod_new_board() { header('Location: ?/' . $board['uri'] . '/' . $config['file_index'], true, $config['redirect_http']); } - mod_page(_('New board'), 'mod/board.html', array('new' => true)); + mod_page(_('New board'), 'mod/board.html', array('new' => true, 'token' => make_secure_link_token('new-board'))); } function mod_noticeboard($page_no = 1) { @@ -502,11 +507,19 @@ function mod_noticeboard($page_no = 1) { if (empty($noticeboard) && $page_no > 1) error($config['error']['404']); + foreach ($noticeboard as &$entry) { + $entry['delete_token'] = make_secure_link_token('noticeboard/delete/' . $entry['id']); + } + $query = prepare("SELECT COUNT(*) FROM ``noticeboard``"); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - mod_page(_('Noticeboard'), 'mod/noticeboard.html', array('noticeboard' => $noticeboard, 'count' => $count)); + mod_page(_('Noticeboard'), 'mod/noticeboard.html', array( + 'noticeboard' => $noticeboard, + 'count' => $count, + 'token' => make_secure_link_token('noticeboard') + )); } function mod_noticeboard_delete($id) { @@ -563,11 +576,15 @@ function mod_news($page_no = 1) { if (empty($news) && $page_no > 1) error($config['error']['404']); + foreach ($news as &$entry) { + $entry['delete_token'] = make_secure_link_token('news/delete/' . $entry['id']); + } + $query = prepare("SELECT COUNT(*) FROM ``news``"); $query->execute() or error(db_error($query)); $count = $query->fetchColumn(); - mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count)); + mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('news'))); } function mod_news_delete($id) { @@ -773,6 +790,8 @@ function mod_page_ip($ip) { $args['logs'] = array(); } + $args['security_token'] = make_secure_link_token('IP/' . $ip); + mod_page(sprintf('%s: %s', _('IP'), $ip), 'mod/view_ip.html', $args, $args['hostname']); } @@ -835,7 +854,11 @@ function mod_bans($page_no = 1) { $ban['single_addr'] = true; } - mod_page(_('Ban list'), 'mod/ban_list.html', array('bans' => $bans, 'count' => Bans::count())); + mod_page(_('Ban list'), 'mod/ban_list.html', array( + 'bans' => $bans, + 'count' => Bans::count(), + 'token' => make_secure_link_token('bans') + )); } function mod_ban_appeals() { @@ -851,15 +874,23 @@ function mod_ban_appeals() { if (isset($_POST['appeal_id']) && (isset($_POST['unban']) || isset($_POST['deny']))) { if (!hasPermission($config['mod']['ban_appeals'])) error($config['error']['noaccess']); + + $query = query("SELECT *, ``ban_appeals``.`id` AS `id` FROM ``ban_appeals`` + LEFT JOIN ``bans`` ON `ban_id` = ``bans``.`id` + WHERE ``ban_appeals``.`id` = " . (int)$_POST['appeal_id']) or error(db_error()); + if (!$ban = $query->fetch(PDO::FETCH_ASSOC)) { + error(_('Ban appeal not found!')); + } + + $ban['mask'] = Bans::range_to_string(array($ban['ipstart'], $ban['ipend'])); + if (isset($_POST['unban'])) { - $query = query("SELECT `ban_id` FROM ``ban_appeals`` WHERE `id` = " . - (int)$_POST['appeal_id']) or error(db_error()); - if ($ban_id = $query->fetchColumn()) { - Bans::delete($ban_id); - query("DELETE FROM ``ban_appeals`` WHERE `id` = " . (int)$_POST['appeal_id']) or error(db_error()); - } + modLog('Accepted ban appeal #' . $ban['id'] . ' for ' . $ban['mask']); + Bans::delete($ban['ban_id'], true); + query("DELETE FROM ``ban_appeals`` WHERE `id` = " . $ban['id']) or error(db_error()); } else { - query("UPDATE ``ban_appeals`` SET `denied` = 1 WHERE `id` = " . (int)$_POST['appeal_id']) or error(db_error()); + modLog('Denied ban appeal #' . $ban['id'] . ' for ' . $ban['mask']); + query("UPDATE ``ban_appeals`` SET `denied` = 1 WHERE `id` = " . $ban['id']) or error(db_error()); } header('Location: ?/ban-appeals', true, $config['redirect_http']); @@ -898,7 +929,10 @@ function mod_ban_appeals() { } } - mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array('ban_appeals' => $ban_appeals)); + mod_page(_('Ban appeals'), 'mod/ban_appeals.html', array( + 'ban_appeals' => $ban_appeals, + 'token' => make_secure_link_token('ban-appeals') + )); } function mod_lock($board, $unlock, $post) { @@ -1583,7 +1617,12 @@ function mod_user($uid) { $user['boards'] = explode(',', $user['boards']); - mod_page(_('Edit user'), 'mod/user.html', array('user' => $user, 'logs' => $log, 'boards' => listBoards())); + mod_page(_('Edit user'), 'mod/user.html', array( + 'user' => $user, + 'logs' => $log, + 'boards' => listBoards(), + 'token' => make_secure_link_token('users/' . $user['id']) + )); } function mod_user_new() { @@ -1636,7 +1675,7 @@ function mod_user_new() { return; } - mod_page(_('Edit user'), 'mod/user.html', array('new' => true, 'boards' => listBoards())); + mod_page(_('New user'), 'mod/user.html', array('new' => true, 'boards' => listBoards(), 'token' => make_secure_link_token('users/new'))); } @@ -1646,9 +1685,18 @@ function mod_users() { if (!hasPermission($config['mod']['manageusers'])) error($config['error']['noaccess']); - $query = query("SELECT *, (SELECT `time` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `last`, (SELECT `text` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `action` FROM ``mods`` ORDER BY `type` DESC,`id`") or error(db_error()); + $query = query("SELECT + *, + (SELECT `time` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `last`, + (SELECT `text` FROM ``modlogs`` WHERE `mod` = `id` ORDER BY `time` DESC LIMIT 1) AS `action` + FROM ``mods`` ORDER BY `type` DESC,`id`") or error(db_error()); $users = $query->fetchAll(PDO::FETCH_ASSOC); + foreach ($users as &$user) { + $user['promote_token'] = make_secure_link_token("users/{$user['id']}/promote"); + $user['demote_token'] = make_secure_link_token("users/{$user['id']}/demote"); + } + mod_page(sprintf('%s (%d)', _('Manage users'), count($users)), 'mod/users.html', array('users' => $users)); } @@ -1740,7 +1788,10 @@ function mod_pm($id, $reply = false) { error($config['error']['404']); // deleted? mod_page(sprintf('%s %s', _('New PM for'), $pm['to_username']), 'mod/new_pm.html', array( - 'username' => $pm['username'], 'id' => $pm['sender'], 'message' => quote($pm['message']) + 'username' => $pm['username'], + 'id' => $pm['sender'], + 'message' => quote($pm['message']), + 'token' => make_secure_link_token('new_PM/' . $pm['username']) )); } else { mod_page(sprintf('%s – #%d', _('Private message'), $id), 'mod/pm.html', $pm); @@ -1812,7 +1863,11 @@ function mod_new_pm($username) { header('Location: ?/', true, $config['redirect_http']); } - mod_page(sprintf('%s %s', _('New PM for'), $username), 'mod/new_pm.html', array('username' => $username, 'id' => $id)); + mod_page(sprintf('%s %s', _('New PM for'), $username), 'mod/new_pm.html', array( + 'username' => $username, + 'id' => $id, + 'token' => make_secure_link_token('new_PM/' . $username) + )); } function mod_rebuild() { @@ -1881,7 +1936,10 @@ function mod_rebuild() { return; } - mod_page(_('Rebuild'), 'mod/rebuild.html', array('boards' => listBoards())); + mod_page(_('Rebuild'), 'mod/rebuild.html', array( + 'boards' => listBoards(), + 'token' => make_secure_link_token('rebuild') + )); } function mod_reports() { @@ -1936,7 +1994,13 @@ function mod_reports() { } // a little messy and inefficient - $append_html = Element('mod/report.html', array('report' => $report, 'config' => $config, 'mod' => $mod)); + $append_html = Element('mod/report.html', array( + 'report' => $report, + 'config' => $config, + 'mod' => $mod, + 'token' => make_secure_link_token('reports/' . $report['id'] . '/dismiss'), + 'token_all' => make_secure_link_token('reports/' . $report['id'] . '/dismissall') + )); // Bug fix for https://github.com/savetheinternet/Tinyboard/issues/21 $po->body = truncate($po->body, $po->link(), $config['body_truncate'] - substr_count($append_html, '
')); @@ -2030,7 +2094,8 @@ function mod_config($board_config = false) { 'readonly' => $readonly, 'boards' => listBoards(), 'board' => $board_config, - 'file' => $config_file + 'file' => $config_file, + 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) )); return; } @@ -2113,17 +2178,18 @@ function mod_config($board_config = false) { } } - header('Location: ?/config', true, $config['redirect_http']); + header('Location: ?/config' . ($board_config ? '/' . $board_config : ''), true, $config['redirect_http']); exit; } - + mod_page(_('Config editor') . ($board_config ? ': ' . sprintf($config['board_abbreviation'], $board_config) : ''), 'mod/config-editor.html', array( 'boards' => listBoards(), 'board' => $board_config, 'conf' => $conf, - 'file' => $config_file + 'file' => $config_file, + 'token' => make_secure_link_token('config' . ($board_config ? '/' . $board_config : '')) )); } @@ -2149,6 +2215,11 @@ function mod_themes_list() { } } closedir($dir); + + foreach ($themes as $theme_name => &$theme) { + $theme['rebuild_token'] = make_secure_link_token('themes/' . $theme_name . '/rebuild'); + $theme['uninstall_token'] = make_secure_link_token('themes/' . $theme_name . '/uninstall'); + } mod_page(_('Manage themes'), 'mod/themes.html', array( 'themes' => $themes, @@ -2219,7 +2290,7 @@ function mod_theme_configure($theme_name) { 'theme_name' => $theme_name, 'theme' => $theme, 'result' => $result, - 'message' => $message, + 'message' => $message )); return; } @@ -2230,6 +2301,7 @@ function mod_theme_configure($theme_name) { 'theme_name' => $theme_name, 'theme' => $theme, 'settings' => $settings, + 'token' => make_secure_link_token('themes/' . $theme_name) )); } diff --git a/mod.php b/mod.php index cf6423ed..f6a4aa0c 100644 --- a/mod.php +++ b/mod.php @@ -24,49 +24,51 @@ if (get_magic_quotes_gpc()) { $query = isset($_SERVER['QUERY_STRING']) ? rawurldecode($_SERVER['QUERY_STRING']) : ''; $pages = array( - '' => ':?/', // redirect to dashboard - '/' => 'dashboard', // dashboard - '/confirm/(.+)' => 'confirm', // confirm action (if javascript didn't work) - '/logout' => 'logout', // logout + '' => ':?/', // redirect to dashboard + '/' => 'dashboard', // dashboard + '/confirm/(.+)' => 'confirm', // confirm action (if javascript didn't work) + '/logout' => 'secure logout', // logout - '/users' => 'users', // manage users - '/users/(\d+)' => 'user', // edit user - '/users/(\d+)/(promote|demote)' => 'user_promote', // prmote/demote user - '/users/new' => 'user_new', // create a new user - '/new_PM/([^/]+)' => 'new_pm', // create a new pm - '/PM/(\d+)(/reply)?' => 'pm', // read a pm - '/inbox' => 'inbox', // pm inbox + '/users' => 'users', // manage users + '/users/(\d+)/(promote|demote)' => 'secure user_promote', // prmote/demote user + '/users/(\d+)' => 'secure_POST user', // edit user + '/users/new' => 'secure_POST user_new', // create a new user - '/noticeboard' => 'noticeboard', // view noticeboard - '/noticeboard/(\d+)' => 'noticeboard', // view noticeboard - '/noticeboard/delete/(\d+)' => 'noticeboard_delete', // delete from noticeboard - '/log' => 'log', // modlog - '/log/(\d+)' => 'log', // modlog - '/log:([^/]+)' => 'user_log', // modlog - '/log:([^/]+)/(\d+)' => 'user_log', // modlog - '/news' => 'news', // view news - '/news/(\d+)' => 'news', // view news - '/news/delete/(\d+)' => 'news_delete', // delete from news + '/new_PM/([^/]+)' => 'secure_POST new_pm', // create a new pm + '/PM/(\d+)(/reply)?' => 'pm', // read a pm + '/inbox' => 'inbox', // pm inbox - '/edit/(\%b)' => 'edit_board', // edit board details - '/new-board' => 'new_board', // create a new board + '/log' => 'log', // modlog + '/log/(\d+)' => 'log', // modlog + '/log:([^/]+)' => 'user_log', // modlog + '/log:([^/]+)/(\d+)' => 'user_log', // modlog + '/news' => 'secure_POST news', // view news + '/news/(\d+)' => 'secure_POST news', // view news + '/news/delete/(\d+)' => 'secure news_delete', // delete from news - '/rebuild' => 'rebuild', // rebuild static files - '/reports' => 'reports', // report queue - '/reports/(\d+)/dismiss(all)?' => 'report_dismiss', // dismiss a report + '/noticeboard' => 'secure_POST noticeboard', // view noticeboard + '/noticeboard/(\d+)' => 'secure_POST noticeboard', // view noticeboard + '/noticeboard/delete/(\d+)' => 'secure noticeboard_delete', // delete from noticeboard - '/IP/([\w.:]+)' => 'ip', // view ip address - '/IP/([\w.:]+)/remove_note/(\d+)' => 'ip_remove_note', // remove note from ip address - '/bans' => 'bans', // ban list - '/bans/(\d+)' => 'bans', // ban list - '/ban-appeals' => 'ban_appeals', // view ban appeals + '/edit/(\%b)' => 'secure_POST edit_board', // edit board details + '/new-board' => 'secure_POST new_board', // create a new board + + '/rebuild' => 'secure_POST rebuild', // rebuild static files + '/reports' => 'reports', // report queue + '/reports/(\d+)/dismiss(all)?' => 'secure report_dismiss', // dismiss a report + + '/IP/([\w.:]+)' => 'secure_POST ip', // view ip address + '/IP/([\w.:]+)/remove_note/(\d+)' => 'secure ip_remove_note', // remove note from ip address - '/search' => 'search_redirect', // search - '/search/(posts|IP_notes|bans|log)/(.+)/(\d+)' => 'search', // search - '/search/(posts|IP_notes|bans|log)/(.+)' => 'search', // search - - // CSRF-protected moderator actions '/ban' => 'secure_POST ban', // new ban + '/bans' => 'secure_POST bans', // ban list + '/bans/(\d+)' => 'secure_POST bans', // ban list + '/ban-appeals' => 'secure_POST ban_appeals', // view ban appeals + + '/search' => 'search_redirect', // search + '/search/(posts|IP_notes|bans|log)/(.+)/(\d+)' => 'search', // search + '/search/(posts|IP_notes|bans|log)/(.+)' => 'search', // search + '/(\%b)/ban(&delete)?/(\d+)' => 'secure_POST ban_post', // ban poster '/(\%b)/move/(\d+)' => 'secure_POST move', // move thread '/(\%b)/edit(_raw)?/(\d+)' => 'secure_POST edit_post', // edit post @@ -78,13 +80,13 @@ $pages = array( '/(\%b)/(un)?sticky/(\d+)' => 'secure sticky', // sticky thread '/(\%b)/bump(un)?lock/(\d+)' => 'secure bumplock', // "bumplock" thread - '/themes' => 'themes_list', // manage themes - '/themes/(\w+)' => 'theme_configure', // configure/reconfigure theme - '/themes/(\w+)/rebuild' => 'theme_rebuild', // rebuild theme - '/themes/(\w+)/uninstall' => 'theme_uninstall', // uninstall theme + '/themes' => 'themes_list', // manage themes + '/themes/(\w+)' => 'secure_POST theme_configure', // configure/reconfigure theme + '/themes/(\w+)/rebuild' => 'secure theme_rebuild', // rebuild theme + '/themes/(\w+)/uninstall' => 'secure theme_uninstall', // uninstall theme - '/config' => 'config', // config editor - '/config/(\%b)' => 'config', // config editor + '/config' => 'secure_POST config', // config editor + '/config/(\%b)' => 'secure_POST config', // config editor // these pages aren't listed in the dashboard without $config['debug'] '/debug/antispam' => 'debug_antispam', diff --git a/templates/mod/ban_appeals.html b/templates/mod/ban_appeals.html index f43b7db5..23eced12 100644 --- a/templates/mod/ban_appeals.html +++ b/templates/mod/ban_appeals.html @@ -1,6 +1,7 @@ {% for ban in ban_appeals %}
+ diff --git a/templates/mod/ban_list.html b/templates/mod/ban_list.html index b41cef28..97c02029 100644 --- a/templates/mod/ban_list.html +++ b/templates/mod/ban_list.html @@ -1,7 +1,8 @@ {% if bans|count == 0 %}

({% trans 'There are no active bans.' %})

{% else %} - + +
{% trans 'Status' %}
diff --git a/templates/mod/board.html b/templates/mod/board.html index 0775e421..4da597a7 100644 --- a/templates/mod/board.html +++ b/templates/mod/board.html @@ -5,6 +5,7 @@ {% endif %} +
{% trans 'IP address/mask' %}
diff --git a/templates/mod/config-editor-php.html b/templates/mod/config-editor-php.html index 4f76b5dd..0c1a3a09 100644 --- a/templates/mod/config-editor-php.html +++ b/templates/mod/config-editor-php.html @@ -21,6 +21,7 @@ {% if not readonly %}{% endif %} + diff --git a/templates/mod/config-editor.html b/templates/mod/config-editor.html index 4f4cba93..411d55e6 100644 --- a/templates/mod/config-editor.html +++ b/templates/mod/config-editor.html @@ -14,6 +14,7 @@ {% endif %} +
{% trans 'URI' %}
diff --git a/templates/mod/dashboard.html b/templates/mod/dashboard.html index 916f0c03..7b907533 100644 --- a/templates/mod/dashboard.html +++ b/templates/mod/dashboard.html @@ -164,7 +164,7 @@ {% trans 'User account' %} diff --git a/templates/mod/new_pm.html b/templates/mod/new_pm.html index 3fd78ac6..605b0973 100644 --- a/templates/mod/new_pm.html +++ b/templates/mod/new_pm.html @@ -1,4 +1,5 @@ +
{% trans 'Name' %}
diff --git a/templates/mod/news.html b/templates/mod/news.html index b0335e0a..510d60ce 100644 --- a/templates/mod/news.html +++ b/templates/mod/news.html @@ -2,6 +2,7 @@
{% trans 'New post' %} +
To
@@ -39,7 +40,7 @@
{% if mod|hasPermission(config.mod.news_delete) %} - [{% trans 'delete' %}] + [{% trans 'delete' %}] {% endif %}

diff --git a/templates/mod/noticeboard.html b/templates/mod/noticeboard.html index 463b8430..fc2e0aef 100644 --- a/templates/mod/noticeboard.html +++ b/templates/mod/noticeboard.html @@ -1,7 +1,8 @@ {% if mod|hasPermission(config.mod.noticeboard_post) %}
{% trans 'New post' %} - + + @@ -27,7 +28,7 @@
{% if mod|hasPermission(config.mod.noticeboard_delete) %} - [{% trans 'delete' %}] + [{% trans 'delete' %}] {% endif %}

diff --git a/templates/mod/rebuild.html b/templates/mod/rebuild.html index 7c6b28ba..81d1ead3 100644 --- a/templates/mod/rebuild.html +++ b/templates/mod/rebuild.html @@ -1,4 +1,5 @@ +
  • diff --git a/templates/mod/report.html b/templates/mod/report.html index 9c8463ed..b5392d5b 100644 --- a/templates/mod/report.html +++ b/templates/mod/report.html @@ -13,13 +13,13 @@ {% if mod|hasPermission(config.mod.report_dismiss, report.board) or mod|hasPermission(config.mod.report_dismiss_ip, report.board) %}
    {% if mod|hasPermission(config.mod.report_dismiss, report.board) %} - Dismiss + Dismiss {% endif %} {% if mod|hasPermission(config.mod.report_dismiss_ip, report.board) %} {% if mod|hasPermission(config.mod.report_dismiss, report.board) %} | {% endif %} - Dismiss+ + Dismiss+ {% endif %} {% endif %}

diff --git a/templates/mod/theme_config.html b/templates/mod/theme_config.html index d85b5df1..d82a1f14 100644 --- a/templates/mod/theme_config.html +++ b/templates/mod/theme_config.html @@ -1,4 +1,5 @@ + {% if not config %}

(No configuration required.)

{% else %} diff --git a/templates/mod/themes.html b/templates/mod/themes.html index b596826d..b230bc48 100644 --- a/templates/mod/themes.html +++ b/templates/mod/themes.html @@ -28,8 +28,8 @@ {% if theme_name in themes_in_use %}{% trans 'Reconfigure' %}{% else %}{% trans 'Install' %}{% endif %} {% if theme_name in themes_in_use %} -
  • {% trans 'Rebuild' %}
  • -
  • {% trans 'Uninstall' %}
  • +
  • {% trans 'Rebuild' %}
  • +
  • {% trans 'Uninstall' %}
  • {% endif %} diff --git a/templates/mod/user.html b/templates/mod/user.html index 89240824..08598fe5 100644 --- a/templates/mod/user.html +++ b/templates/mod/user.html @@ -5,6 +5,7 @@ {% endif %} +
    {% trans 'Name' %}
    diff --git a/templates/mod/users.html b/templates/mod/users.html index b4c666e1..6f42ce2a 100644 --- a/templates/mod/users.html +++ b/templates/mod/users.html @@ -48,10 +48,10 @@ {% endif %}
    {% trans 'Username' %} {% if mod|hasPermission(config.mod.promoteusers) and user.type < constant(config.mod.groups[0:-1]|last) %} - ▲ + ▲ {% endif %} {% if mod|hasPermission(config.mod.promoteusers) and user.type > constant(config.mod.groups|first) %} - ▼ + ▼ {% endif %} {% if mod|hasPermission(config.mod.modlog) %} [{% trans 'log' %}] diff --git a/templates/mod/view_ip.html b/templates/mod/view_ip.html index f73c5d5a..1c1c7fa6 100644 --- a/templates/mod/view_ip.html +++ b/templates/mod/view_ip.html @@ -57,6 +57,7 @@ {% if mod|hasPermission(config.mod.create_notes) %} + @@ -87,6 +88,7 @@ {% for ban in bans %} +
    {% trans 'Staff' %}
    -- cgit v1.3 From f5422cad65e5cafd7d53da87d62a6fc247da3b1b Mon Sep 17 00:00:00 2001 From: Michael Foster Date: Mon, 30 Sep 2013 12:18:56 +1000 Subject: Um. I accidentally deleted this code for some reason. --- inc/mod/pages.php | 54 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 5 deletions(-) (limited to 'inc/mod/pages.php') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 58cd5c26..c091263e 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -199,27 +199,71 @@ function mod_search($type, $search_query_escaped, $page_no = 1) { // Form a series of LIKE clauses for the query. // This gets a little complicated. - + // Escape "escape" character + $query = str_replace('!', '!!', $query); + + // Escape SQL wildcard + $query = str_replace('%', '!%', $query); + + // Use asterisk as wildcard instead + $query = str_replace('*', '%', $query); + + $query = str_replace('`', '!`', $query); + + // Array of phrases to match + $match = array(); + + // Exact phrases ("like this") + if (preg_match_all('/"(.+?)"/', $query, $exact_phrases)) { + $exact_phrases = $exact_phrases[1]; + foreach ($exact_phrases as $phrase) { + $query = str_replace("\"{$phrase}\"", '', $query); + $match[] = $pdo->quote($phrase); + } + } + + // Non-exact phrases (ie. plain keywords) + $keywords = explode(' ', $query); + foreach ($keywords as $word) { + if (empty($word)) + continue; + $match[] = $pdo->quote($word); + } + // Which `field` to search? if ($type == 'posts') - $sql_field = array('body_nomarkup', 'filename', 'subject', 'filehash', 'ip', 'name', 'trip'); + $sql_field = array('body_nomarkup', 'filename', 'file', 'subject', 'filehash', 'ip', 'name', 'trip'); if ($type == 'IP_notes') $sql_field = 'body'; if ($type == 'bans') $sql_field = 'reason'; if ($type == 'log') $sql_field = 'text'; - + + // Build the "LIKE 'this' AND LIKE 'that'" etc. part of the SQL query + $sql_like = ''; + foreach ($match as $phrase) { + if (!empty($sql_like)) + $sql_like .= ' AND '; + $phrase = preg_replace('/^\'(.+)\'$/', '\'%$1%\'', $phrase); + if (is_array($sql_field)) { + foreach ($sql_field as $field) { + $sql_like .= '`' . $field . '` LIKE ' . $phrase . ' ESCAPE \'!\' OR'; + } + $sql_like = preg_replace('/ OR$/', '', $sql_like); + } else { + $sql_like .= '`' . $sql_field . '` LIKE ' . $phrase . ' ESCAPE \'!\''; + } + } // Compile SQL query if ($type == 'posts') { $query = ''; - $boards = listBoards(); if (empty($boards)) error(_('There are no boards to search!')); - + foreach ($boards as $board) { openBoard($board['uri']); if (!hasPermission($config['mod']['search_posts'], $board['uri'])) -- cgit v1.3
    {% trans 'Status' %}