diff --git a/.gitignore b/.gitignore
index add30777..5bc45780 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,5 @@ Thumbs.db
#vichan custom
favicon.ico
/static/spoiler.png
+
+/inc/locale/ja_JP/*
diff --git a/inc/functions.php b/inc/functions.php
index d1b1410b..85146834 100755
--- a/inc/functions.php
+++ b/inc/functions.php
@@ -335,7 +335,7 @@ function create_antibot($board, $thread = null) {
}
function rebuildThemes($action, $boardname = false) {
- global $config, $board, $current_locale;
+ global $config, $board, $current_locale, $error;
// Save the global variables
$_config = $config;
@@ -2406,3 +2406,31 @@ function diceRoller($post) {
}
}
}
+
+function less_ip($ip) {
+ $ipv6 = (strstr($ip, ':') !== false);
+
+ $in_addr = inet_pton($ip);
+
+ if ($ipv6) {
+ // Not sure how many to mask for IPv6, opinions?
+ $mask = inet_pton('ffff:ffff:ffff:ffff:ffff:0:0:0');
+ } else {
+ $mask = inet_pton('255.255.0.0');
+ }
+
+ $final = inet_ntop($in_addr & $mask);
+ return str_replace(array(':0', '.0'), array(':x', '.x'), $final);
+}
+
+function less_hostmask($hostmask) {
+ $parts = explode('.', $hostmask);
+
+ if (sizeof($parts) < 3)
+ return $hostmask;
+
+ $parts[0] = 'x';
+ $parts[1] = 'x';
+
+ return implode('.', $parts);
+}
diff --git a/inc/instance-config.php b/inc/instance-config.php
index cebf00c8..ee5474e0 100644
--- a/inc/instance-config.php
+++ b/inc/instance-config.php
@@ -77,6 +77,8 @@
' %s',
);
//$config['mod']['view_banlist'] = SUPERMOD;
+ $config['mod']['show_ip'] = SUPERMOD;
+ $config['mod']['show_ip_less'] = MOD;
$config['mod']['manageusers'] = SUPERMOD;
$config['mod']['noticeboard_post'] = SUPERMOD;
$config['mod']['search'] = SUPERMOD;
diff --git a/inc/lib/Twig/Extensions/Extension/Tinyboard.php b/inc/lib/Twig/Extensions/Extension/Tinyboard.php
index 75af6890..65578582 100644
--- a/inc/lib/Twig/Extensions/Extension/Tinyboard.php
+++ b/inc/lib/Twig/Extensions/Extension/Tinyboard.php
@@ -20,6 +20,7 @@ class Twig_Extensions_Extension_Tinyboard extends Twig_Extension
new Twig_SimpleFilter('hasPermission', 'twig_hasPermission_filter'),
new Twig_SimpleFilter('date', 'twig_date_filter'),
new Twig_SimpleFilter('remove_whitespace', 'twig_remove_whitespace_filter'),
+ new Twig_SimpleFilter('less_ip', 'twig_less_ip'),
new Twig_SimpleFilter('count', 'count'),
new Twig_SimpleFilter('ago', 'ago'),
new Twig_SimpleFilter('until', 'until'),
@@ -131,3 +132,6 @@ function twig_secure_link_confirm($text, $title, $confirm_message, $href) {
function twig_secure_link($href) {
return $href . '/' . make_secure_link_token($href);
}
+function twig_less_ip($ip) {
+ return less_ip($ip);
+}
diff --git a/inc/mod/pages.php b/inc/mod/pages.php
index 2bb14be9..95375914 100644
--- a/inc/mod/pages.php
+++ b/inc/mod/pages.php
@@ -775,6 +775,9 @@ function mod_ip_remove_note($ip, $id) {
function mod_page_ip($ip) {
global $config, $mod;
+
+ if (!hasPermission($config['mod']['show_ip']))
+ error($config['error']['noaccess']);
if (filter_var($ip, FILTER_VALIDATE_IP) === false)
error("Invalid IP address.");
@@ -865,6 +868,107 @@ function mod_page_ip($ip) {
mod_page(sprintf('%s: %s', _('IP'), $ip), 'mod/view_ip.html', $args, $args['hostname']);
}
+function mod_page_ip_less($b, $id) {
+ global $config, $mod;
+
+ $query = prepare(sprintf('SELECT `ip` FROM ``posts_%s`` WHERE `id` = :id', $b));
+ $query->bindValue(':id', $id);
+ $query->execute() or error(db_error($query));
+
+ $result = $query->fetch(PDO::FETCH_ASSOC);
+
+ if ($result) {
+ $ip = $result['ip'];
+ } else {
+ error(_('Could not find that post.'));
+ }
+
+ if (filter_var($ip, FILTER_VALIDATE_IP) === false)
+ error("Invalid IP address.");
+
+ if (isset($_POST['ban_id'], $_POST['unban'])) {
+ if (!hasPermission($config['mod']['unban']))
+ error($config['error']['noaccess']);
+
+ Bans::delete($_POST['ban_id'], true);
+
+ header('Location: ?/IP/' . $ip . '#bans', true, $config['redirect_http']);
+ return;
+ }
+
+ if (isset($_POST['note'])) {
+ if (!hasPermission($config['mod']['create_notes']))
+ error($config['error']['noaccess']);
+
+ $_POST['note'] = escape_markup_modifiers($_POST['note']);
+ markup($_POST['note']);
+ $query = prepare('INSERT INTO ``ip_notes`` VALUES (NULL, :ip, :mod, :time, :body)');
+ $query->bindValue(':ip', $ip);
+ $query->bindValue(':mod', $mod['id']);
+ $query->bindValue(':time', time());
+ $query->bindValue(':body', $_POST['note']);
+ $query->execute() or error(db_error($query));
+
+ modLog("Added a note for {$ip}");
+
+ header('Location: ?/IP/' . $ip . '#notes', true, $config['redirect_http']);
+ return;
+ }
+
+ $args = array();
+ $args['ip'] = $ip;
+ $args['posts'] = array();
+
+ if ($config['mod']['dns_lookup'])
+ $args['hostname'] = rDNS($ip);
+
+ openBoard($b);
+
+ $query = prepare(sprintf('SELECT * FROM ``posts_%s`` WHERE `ip` = :ip ORDER BY `sticky` DESC, `id` DESC LIMIT :limit', $b));
+ $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(PDO::FETCH_ASSOC)) {
+ if (!$post['thread']) {
+ $po = new Thread($post, '?/', $mod, false);
+ } else {
+ $po = new Post($post, '?/', $mod);
+ }
+
+ if (!isset($args['posts'][$b]))
+ $args['posts'][$b] = array('board' => $b, 'posts' => array());
+ $args['posts'][$b]['posts'][] = $po->build(true);
+ }
+
+ $args['boards'] = listBoards();
+ $args['token'] = make_secure_link_token('ban');
+
+ if (hasPermission($config['mod']['view_ban'])) {
+ $args['bans'] = Bans::find($ip, false, true);
+ }
+
+ if (hasPermission($config['mod']['view_notes'])) {
+ $query = prepare("SELECT ``ip_notes``.*, `username` FROM ``ip_notes`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `ip` = :ip ORDER BY `time` DESC");
+ $query->bindValue(':ip', $ip);
+ $query->execute() or error(db_error($query));
+ $args['notes'] = $query->fetchAll(PDO::FETCH_ASSOC);
+ }
+
+ if (hasPermission($config['mod']['modlog_ip'])) {
+ $query = prepare("SELECT `username`, `mod`, `ip`, `board`, `time`, `text` FROM ``modlogs`` LEFT JOIN ``mods`` ON `mod` = ``mods``.`id` WHERE `text` LIKE :search ORDER BY `time` DESC LIMIT 50");
+ $query->bindValue(':search', '%' . $ip . '%');
+ $query->execute() or error(db_error($query));
+ $args['logs'] = $query->fetchAll(PDO::FETCH_ASSOC);
+ } else {
+ $args['logs'] = array();
+ }
+
+ $args['security_token'] = make_secure_link_token('IP_less/' . $b . '/' . $id);
+
+ mod_page(sprintf('%s: %s', _('IP'), less_ip($ip)), 'mod/view_ip_less.html', $args, less_hostmask($args['hostname']));
+}
+
function mod_ban() {
global $config, $mod;
@@ -1417,8 +1521,11 @@ function mod_ban_post($board, $delete, $post, $token = false) {
if (isset($_POST['ip']))
$ip = $_POST['ip'];
+
+ if (isset($_POST['range']))
+ $ip = $ip . $_POST['range'];
- Bans::new_ban($_POST['ip'], $_POST['reason'], $_POST['length'], $_POST['board'] == '*' ? false : $_POST['board'],
+ Bans::new_ban($ip, $_POST['reason'], $_POST['length'], $_POST['board'] == '*' ? false : $_POST['board'],
false, $config['ban_show_post'] ? $_post : false);
if (isset($_POST['public_message'], $_POST['message'])) {
diff --git a/mod.php b/mod.php
index 3f14e2ed..654d23fe 100644
--- a/mod.php
+++ b/mod.php
@@ -60,6 +60,8 @@ $pages = array(
'/IP/([\w.:]+)' => 'secure_POST ip', // view ip address
'/IP/([\w.:]+)/remove_note/(\d+)' => 'secure ip_remove_note', // remove note from ip address
+ '/IP_less/(\%b)/(\d+)' => 'secure_POST ip_less', // view ip address (limited for user privacy)
+ '/IP_less/([\w.:]+)/remove_note/(\d+)' => 'secure ip_remove_note', // remove note from ip address
'/ban' => 'secure_POST ban', // new ban
'/bans' => 'secure_POST bans', // ban list
diff --git a/templates/mod/ban_form.html b/templates/mod/ban_form.html
index 01cfc0a0..bf91594e 100644
--- a/templates/mod/ban_form.html
+++ b/templates/mod/ban_form.html
@@ -23,7 +23,13 @@
{% if not hide_ip %}
{% else %}
- {% trans 'hidden' %}
+ {{ ip|less_ip }}
+
{% endif %}
diff --git a/templates/mod/view_ip_less.html b/templates/mod/view_ip_less.html
new file mode 100644
index 00000000..a93ee6a3
--- /dev/null
+++ b/templates/mod/view_ip_less.html
@@ -0,0 +1,170 @@
+{% for board_posts in posts %}
+ {% if board_posts.board in mod.boards or mod.boards.0 == '*' %}
+