From 7911c374e86ef8fa69c4545867b9d9d3de12d5c6 Mon Sep 17 00:00:00 2001 From: 8chan Date: Wed, 25 Feb 2015 17:21:49 -0800 Subject: Public action logs commit (log.php) Note: In a previous commit, I began making inc/mod/auth.php more modular with the check_login() function. Including it does NOT check mod login by default anymore like it does on vichan. You have to call check_login(). I've finally included it in inc/functions.php. If you have any custom pages that use inc/mod/auth.php, just including functions.php is enough now. =================================== Also: backports 351375185e5 (early 404) --- templates/mod/log.html | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'templates/mod') diff --git a/templates/mod/log.html b/templates/mod/log.html index 0aa3f110..a38b4af5 100644 --- a/templates/mod/log.html +++ b/templates/mod/log.html @@ -10,7 +10,15 @@ {% if log.username %} - {{ log.username|e }} + {% if hide_names %} + hidden + {% else %} + {% if not mod|hasPermission(config.mod.modlog) %} + {{ log.username|e }} + {% else %} + {{ log.username|e }} + {% endif %} + {% endif %} {% elseif log.mod == -1 %} system {% else %} @@ -44,7 +52,11 @@ {% if count > logs|count %}

{% for i in range(0, (count - 1) / config.mod.modlog_page) %} - [{{ i + 1 }}] + {% if public %} + [{{ i + 1 }}] + {% else %} + [{{ i + 1 }}] + {% endif %} {% endfor %}

{% endif %} -- cgit v1.3 From 95b1e103cb9f349d7d82dca071636d5cde855ead Mon Sep 17 00:00:00 2001 From: Fredrick Brennan Date: Sun, 29 Mar 2015 09:18:14 +0800 Subject: Edit static pages commit --- .gitmodules | 6 ++ inc/config.php | 6 ++ inc/functions.php | 43 ++++++++++++ inc/mod/pages.php | 162 +++++++++++++++++++++++++++++++++++++++++++ install.sql | 20 +++++- mod.php | 18 +++-- templates/mod/edit_page.html | 29 ++++++++ templates/mod/pages.html | 34 +++++++++ tools/import_rules.php | 16 +++++ 9 files changed, 328 insertions(+), 6 deletions(-) create mode 100644 templates/mod/edit_page.html create mode 100644 templates/mod/pages.html create mode 100644 tools/import_rules.php (limited to 'templates/mod') diff --git a/.gitmodules b/.gitmodules index 73f90e0a..df07fdf3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "js/wPaint"] path = js/wPaint url = https://github.com/vichan-devel/wPaint.git + branch = master + +[submodule "inc/lib/parsedown"] + path = inc/lib/parsedown + url = https://github.com/vichan-devel/parsedown + branch = master diff --git a/inc/config.php b/inc/config.php index b6bc3b69..3fdb8d2f 100644 --- a/inc/config.php +++ b/inc/config.php @@ -1498,6 +1498,9 @@ $config['mod']['ban_appeals'] = MOD; // View the recent posts page $config['mod']['recent'] = MOD; + // Create pages + $config['mod']['edit_pages'] = MOD; + $config['pages_max'] = 10; // Config editor permissions $config['mod']['config'] = array(); @@ -1702,3 +1705,6 @@ // Use CAPTCHA for reports? $config['report_captcha'] = false; + + // Allowed HTML tags in ?/edit_pages. + $config['allowed_html'] = 'a[href|title],p,br,li,ol,ul,strong,em,u,h2,b,i,tt,div,img[src|alt|title],hr'; diff --git a/inc/functions.php b/inc/functions.php index 378e40b3..7970d05a 100755 --- a/inc/functions.php +++ b/inc/functions.php @@ -20,6 +20,7 @@ require_once 'inc/events.php'; require_once 'inc/api.php'; require_once 'inc/mod/auth.php'; require_once 'inc/polyfill.php'; +//require_once 'inc/lib/parsedown/Parsedown.php'; // we don't need that right now, do we? if (!extension_loaded('gettext')) { require_once 'inc/lib/gettext/gettext.inc'; @@ -2739,3 +2740,45 @@ function link_for($post, $page50 = false, $foreignlink = false, $thread = false) return sprintf($tpl, $id, $slug); } + +function prettify_textarea($s){ + return str_replace("\t", ' ', str_replace("\n", ' ', htmlentities($s))); +} + +class HTMLPurifier_URIFilter_NoExternalImages extends HTMLPurifier_URIFilter { + public $name = 'NoExternalImages'; + public function filter(&$uri, $c, $context) { + global $config; + $ct = $context->get('CurrentToken'); + + if (!$ct || $ct->name !== 'img') return true; + + if (!isset($uri->host) && !isset($uri->scheme)) return true; + + if (!in_array($uri->scheme . '://' . $uri->host . '/', $config['allowed_offsite_urls'])) { + error('No off-site links in board announcement images.'); + } + + return true; + } +} + +function purify_html($s) { + global $config; + + $c = HTMLPurifier_Config::createDefault(); + $c->set('HTML.Allowed', $config['allowed_html']); + $uri = $c->getDefinition('URI'); + $uri->addFilter(new HTMLPurifier_URIFilter_NoExternalImages(), $c); + $purifier = new HTMLPurifier($c); + $clean_html = $purifier->purify($s); + return $clean_html; +} + +function markdown($s) { + $pd = new Parsedown(); + $pd->setMarkupEscaped(true); + $pd->setimagesEnabled(false); + + return $pd->text($s); +} diff --git a/inc/mod/pages.php b/inc/mod/pages.php index ca12eaf1..328380d8 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -2628,6 +2628,167 @@ function mod_theme_rebuild($theme_name) { )); } +// This needs to be done for `secure` CSRF prevention compatibility, otherwise the $board will be read in as the token if editing global pages. +function delete_page_base($page = '', $board = false) { + global $config, $mod; + + if (empty($board)) + $board = false; + + if (!$board && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); + + if (!hasPermission($config['mod']['edit_pages'], $board)) + error($config['error']['noaccess']); + + if ($board !== FALSE && !openBoard($board)) + error($config['error']['noboard']); + + if ($board) { + $query = prepare('DELETE FROM ``pages`` WHERE `board` = :board AND `name` = :name'); + $query->bindValue(':board', ($board ? $board : NULL)); + } else { + $query = prepare('DELETE FROM ``pages`` WHERE `board` IS NULL AND `name` = :name'); + } + $query->bindValue(':name', $page); + $query->execute() or error(db_error($query)); + + header('Location: ?/edit_pages' . ($board ? ('/' . $board) : ''), true, $config['redirect_http']); +} + +function mod_delete_page($page = '') { + delete_page_base($page); +} + +function mod_delete_page_board($page = '', $board = false) { + delete_page_base($page, $board); +} + +function mod_edit_page($id) { + global $config, $mod, $board; + + $query = prepare('SELECT * FROM ``pages`` WHERE `id` = :id'); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + $page = $query->fetch(); + + if (!$page) + error(_('Could not find the page you are trying to edit.')); + + if (!$page['board'] && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); + + if (!hasPermission($config['mod']['edit_pages'], $page['board'])) + error($config['error']['noaccess']); + + if ($page['board'] && !openBoard($page['board'])) + error($config['error']['noboard']); + + if (isset($_POST['method'], $_POST['content'])) { + $content = $_POST['content']; + $method = $_POST['method']; + $page['type'] = $method; + + if (!in_array($method, array('markdown', 'html', 'infinity'))) + error(_('Unrecognized page markup method.')); + + switch ($method) { + case 'markdown': + $write = markdown($content); + break; + case 'html': + if (hasPermission($config['mod']['rawhtml'])) { + $write = $content; + } else { + $write = purify_html($content); + } + break; + case 'infinity': + $c = $content; + markup($content); + $write = $content; + $content = $c; + } + + if (!isset($write) or !$write) + error(_('Failed to mark up your input for some reason...')); + + $query = prepare('UPDATE ``pages`` SET `type` = :method, `content` = :content WHERE `id` = :id'); + $query->bindValue(':method', $method); + $query->bindValue(':content', $content); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + + $fn = ($board['uri'] ? ($board['uri'] . '/') : '') . $page['name'] . '.html'; + $body = "
$write
"; + $html = Element('page.html', array('config' => $config, 'body' => $body, 'title' => utf8tohtml($page['title']))); + file_write($fn, $html); + } + + if (!isset($content)) { + $query = prepare('SELECT `content` FROM ``pages`` WHERE `id` = :id'); + $query->bindValue(':id', $id); + $query->execute() or error(db_error($query)); + $content = $query->fetchColumn(); + } + + mod_page(sprintf(_('Editing static page: %s'), $page['name']), 'mod/edit_page.html', array('page' => $page, 'token' => make_secure_link_token("edit_page/$id"), 'content' => prettify_textarea($content), 'board' => $board)); +} + +function mod_pages($board = false) { + global $config, $mod, $pdo; + + if (empty($board)) + $board = false; + + if (!$board && $mod['boards'][0] !== '*') + error($config['error']['noaccess']); + + if (!hasPermission($config['mod']['edit_pages'], $board)) + error($config['error']['noaccess']); + + if ($board !== FALSE && !openBoard($board)) + error($config['error']['noboard']); + + if ($board) { + $query = prepare('SELECT * FROM ``pages`` WHERE `board` = :board'); + $query->bindValue(':board', $board); + } else { + $query = query('SELECT * FROM ``pages`` WHERE `board` IS NULL'); + } + $query->execute() or error(db_error($query)); + $pages = $query->fetchAll(PDO::FETCH_ASSOC); + + if (isset($_POST['page'])) { + if ($board and sizeof($pages) > $config['pages_max']) + error(sprintf(_('Sorry, this site only allows %d pages per board.'), $config['pages_max'])); + + if (!preg_match('/^[a-z0-9]{1,255}$/', $_POST['page'])) + error(_('Page names must be < 255 chars and may only contain lowercase letters A-Z and digits 1-9.')); + + foreach ($pages as $i => $p) { + if ($_POST['page'] === $p['name']) + error(_('Refusing to create a new page with the same name as an existing one.')); + } + + $title = ($_POST['title'] ? $_POST['title'] : NULL); + + $query = prepare('INSERT INTO ``pages``(board, title, name) VALUES(:board, :title, :name)'); + $query->bindValue(':board', ($board ? $board : NULL)); + $query->bindValue(':title', $title); + $query->bindValue(':name', $_POST['page']); + $query->execute() or error(db_error($query)); + + $pages[] = array('id' => $pdo->lastInsertId(), 'name' => $_POST['page'], 'board' => $board, 'title' => $title); + } + + foreach ($pages as $i => &$p) { + $p['delete_token'] = make_secure_link_token('edit_pages/delete/' . $p['name'] . ($board ? ('/' . $board) : '')); + } + + mod_page(_('Pages'), 'mod/pages.html', array('pages' => $pages, 'token' => make_secure_link_token('edit_pages' . ($board ? ('/' . $board) : '')), 'board' => $board)); +} + function mod_debug_antispam() { global $pdo, $config; @@ -2744,3 +2905,4 @@ function mod_debug_apc() { mod_page(_('Debug: APC'), 'mod/debug/apc.html', array('cached_vars' => $cached_vars)); } + diff --git a/install.sql b/install.sql index 024cb349..720e4ed5 100644 --- a/install.sql +++ b/install.sql @@ -245,7 +245,7 @@ CREATE TABLE IF NOT EXISTS `search_queries` ( `ip` varchar(39) NOT NULL, `time` int(11) NOT NULL, `query` text NOT NULL -) ENGINE=MyISAM DEFAULT CHARSET=utf8; +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; -- -------------------------------------------------------- @@ -297,6 +297,24 @@ CREATE TABLE IF NOT EXISTS `ban_appeals` ( KEY `ban_id` (`ban_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1 ; +-- -------------------------------------------------------- + +-- +-- Table structure for table `pages` +-- + +CREATE TABLE `pages` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `board` varchar(255) DEFAULT NULL, + `name` varchar(255) NOT NULL, + `title` varchar(255) DEFAULT NULL, + `type` varchar(255) DEFAULT NULL, + `content` text, + PRIMARY KEY (`id`), + UNIQUE KEY `u_pages` (`name`,`board`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4; + +>>>>>>> 12fa8ec... Edit static pages commit /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; diff --git a/mod.php b/mod.php index a6ff00cf..fbe679ac 100644 --- a/mod.php +++ b/mod.php @@ -33,11 +33,19 @@ $pages = array( '/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 + '/log:([^/:]+)' => 'user_log', // modlog + '/log:([^/:]+)/(\d+)' => 'user_log', // modlog + '/log:b:([^/]+)' => 'board_log', // modlog + '/log:b:([^/]+)/(\d+)' => 'board_log', // modlog + + '/edit_news' => 'secure_POST news', // view news + '/edit_news/(\d+)' => 'secure_POST news', // view news + '/edit_news/delete/(\d+)' => 'secure news_delete', // delete from news + + '/edit_pages(?:/?(\%b)?)' => 'secure_POST pages', + '/edit_page/(\d+)' => 'secure_POST edit_page', + '/edit_pages/delete/([a-z0-9]+)' => 'secure delete_page', + '/edit_pages/delete/([a-z0-9]+)/(\%b)' => 'secure delete_page_board', '/noticeboard' => 'secure_POST noticeboard', // view noticeboard '/noticeboard/(\d+)' => 'secure_POST noticeboard', // view noticeboard diff --git a/templates/mod/edit_page.html b/templates/mod/edit_page.html new file mode 100644 index 00000000..3d132767 --- /dev/null +++ b/templates/mod/edit_page.html @@ -0,0 +1,29 @@ +
+
+ + + + + + +
{% trans %}Markup method{% endtrans %} + {% set allowed_html = config.allowed_html %} + {% trans %}

"markdown" is provided by parsedown. Note: images disabled.

+

"html" allows the following tags:
{{ allowed_html }}

+

"infinity" is the same as what is used in posts.

+

This page will not convert between formats,
choose it once or do the conversion yourself!

{% endtrans %} +
+ +
{% trans %}Page content{% endtrans %} +
+ {% trans %}Page will appear at:{% endtrans %} + {% if board %} {{ config.domain }}/{{ board.uri }}/{{ page.name }}.html + {% else %} {{ config.site }}/{{ page.name }}.html + {% endif %}
+ +
+
diff --git a/templates/mod/pages.html b/templates/mod/pages.html new file mode 100644 index 00000000..c2395c02 --- /dev/null +++ b/templates/mod/pages.html @@ -0,0 +1,34 @@ + +
+

+{% if board %} +{% set page_max = config.pages_max %} +{% trans %}This page allows you to create static pages for your board. The limit is {{ page_max }} pages per board. You will still have to link to your pages somewhere in your board, for example in a sticky or in the board's announcement. To make links in the board's announcement, use <a> HTML tags.{% endtrans %} +{% else %} +{% trans %}This page allows you to create static pages for your imageboard.{% endtrans %} +{% endif %} +

{% trans %}Existing pages{% endtrans %}

+{% if pages %} +
+ + +{% for page in pages %} + +{% endfor %} +{% else %} +No pages yet! +{% endif %} +
{% trans %}URL{% endtrans %}{% trans %}Title{% endtrans %}{% trans %}Edit{% endtrans %}{% trans %}Delete{% endtrans %}
{{ page.name }}{{ page.title }}{% trans %}Edit{% endtrans %}{% trans %}Delete{% endtrans %}
+
+
+

{% trans %}Create a new page{% endtrans %}

+
+ + + + +
{% trans %}URL{% endtrans %}{% trans %}Title{% endtrans %}
+ +
+ +
diff --git a/tools/import_rules.php b/tools/import_rules.php new file mode 100644 index 00000000..f583f035 --- /dev/null +++ b/tools/import_rules.php @@ -0,0 +1,16 @@ + $b) { + $rules = @file_get_contents($b.'/rules.txt'); + if ($rules && !empty(trim($rules))) { + $query = prepare('INSERT INTO ``pages``(name, title, type, board, content) VALUES("rules", "Rules", "html", :board, :content)'); + $query->bindValue(':board', $b); + $query->bindValue(':content', $rules); + $query->execute() or error(db_error($query)); + } +} -- cgit v1.3 From d788131202604a32986c4ba2bfca841c844ff010 Mon Sep 17 00:00:00 2001 From: 8chan Date: Sun, 14 Dec 2014 03:27:26 -0800 Subject: Allow a board called news to exist --- inc/mod/pages.php | 8 ++++---- templates/mod/dashboard.html | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'templates/mod') diff --git a/inc/mod/pages.php b/inc/mod/pages.php index 328380d8..6d1e20b4 100644 --- a/inc/mod/pages.php +++ b/inc/mod/pages.php @@ -608,7 +608,7 @@ function mod_news($page_no = 1) { rebuildThemes('news'); - header('Location: ?/news#' . $pdo->lastInsertId(), true, $config['redirect_http']); + header('Location: ?/edit_news#' . $pdo->lastInsertId(), true, $config['redirect_http']); } $query = prepare("SELECT * FROM ``news`` ORDER BY `id` DESC LIMIT :offset, :limit"); @@ -621,14 +621,14 @@ function mod_news($page_no = 1) { error($config['error']['404']); foreach ($news as &$entry) { - $entry['delete_token'] = make_secure_link_token('news/delete/' . $entry['id']); + $entry['delete_token'] = make_secure_link_token('edit_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, 'token' => make_secure_link_token('news'))); + mod_page(_('News'), 'mod/news.html', array('news' => $news, 'count' => $count, 'token' => make_secure_link_token('edit_news'))); } function mod_news_delete($id) { @@ -643,7 +643,7 @@ function mod_news_delete($id) { modLog('Deleted a news entry'); - header('Location: ?/news', true, $config['redirect_http']); + header('Location: ?/edit_news', true, $config['redirect_http']); } function mod_log($page_no = 1) { diff --git a/templates/mod/dashboard.html b/templates/mod/dashboard.html index 7e25555b..5c44a522 100644 --- a/templates/mod/dashboard.html +++ b/templates/mod/dashboard.html @@ -62,7 +62,7 @@ {% endif %}
  • {% trans 'View all noticeboard entries' %}
  • {% endif %} -
  • {% trans 'News' %}
  • +
  • {% trans 'News' %}
  • {% trans 'PM inbox' %} -- cgit v1.3 From a5bd39dc4ab2394db7f87d80a01480b22e4a74e1 Mon Sep 17 00:00:00 2001 From: czaks Date: Fri, 6 May 2016 16:49:35 +0200 Subject: mod dashboard html: link to page editor --- templates/mod/dashboard.html | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'templates/mod') diff --git a/templates/mod/dashboard.html b/templates/mod/dashboard.html index 5c44a522..d13bf7f2 100644 --- a/templates/mod/dashboard.html +++ b/templates/mod/dashboard.html @@ -19,6 +19,9 @@ {% if mod|hasPermission(config.mod.manageboards) %} [{% trans 'edit' %}] {% endif %} + {% if mod|hasPermission(config.mod.edit_pages) %} + [{% trans 'pages' %}] + {% endif %}
  • {% endfor %} @@ -100,6 +103,9 @@ {% if mod|hasPermission(config.mod.modlog) %}
  • {% trans 'Moderation log' %}
  • {% endif %} + {% if mod|hasPermission(config.mod.edit_pages) %} +
  • {% trans 'Global static pages' %}
  • + {% endif %} {% if mod|hasPermission(config.mod.recent) %}
  • {% trans 'Recent posts' %}
  • {% endif %} -- cgit v1.3 From 3f405b3484ae6b621ca1fdacbf20e1ef9f3b553a Mon Sep 17 00:00:00 2001 From: czaks Date: Fri, 6 May 2016 16:53:28 +0200 Subject: what if IP address contained bad characters? (highly local) --- templates/mod/ban_form.html | 2 +- templates/mod/view_ip.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'templates/mod') diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html index 6c7560ad..98cc34b2 100644 --- a/templates/mod/ban_form.html +++ b/templates/mod/ban_form.html @@ -21,7 +21,7 @@ {% if not hide_ip %} - + {% else %} {% trans 'hidden' %} {% endif %} diff --git a/templates/mod/view_ip.html b/templates/mod/view_ip.html index 1c1c7fa6..4bacc7f6 100644 --- a/templates/mod/view_ip.html +++ b/templates/mod/view_ip.html @@ -45,7 +45,7 @@ {% if mod|hasPermission(config.mod.remove_notes) %} - + [{% trans 'remove' %}] -- cgit v1.3 From d285a796674f170b0e7a71ffa0cc7bbee2d5421a Mon Sep 17 00:00:00 2001 From: fatchan Date: Tue, 31 May 2016 23:28:55 +1000 Subject: Move the 'Go back and rebuild again' to the top of the rebuilt page so you dont have to scroll --- templates/mod/rebuilt.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'templates/mod') diff --git a/templates/mod/rebuilt.html b/templates/mod/rebuilt.html index 57d16fff..f27cdf56 100644 --- a/templates/mod/rebuilt.html +++ b/templates/mod/rebuilt.html @@ -1,12 +1,12 @@

    {% trans 'Rebuilt' %}

    +

    + {% trans 'Go back and rebuild again' %}. +

      {% for log in logs %}
    • {{ log }}
    • {% endfor %}
    -

    - {% trans 'Go back and rebuild again' %}. -

    -- cgit v1.3 From 94c91db097c034c46f66b27d16eb84a4ea814bb6 Mon Sep 17 00:00:00 2001 From: czaks Date: Thu, 9 Jun 2016 04:51:05 +0200 Subject: fix news deletion; thanks MrFreeman --- templates/mod/news.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'templates/mod') diff --git a/templates/mod/news.html b/templates/mod/news.html index 510d60ce..57058291 100644 --- a/templates/mod/news.html +++ b/templates/mod/news.html @@ -40,7 +40,7 @@
    {% if mod|hasPermission(config.mod.news_delete) %} - [{% trans 'delete' %}] + [{% trans 'delete' %}] {% endif %}

    -- cgit v1.3