The version of vichan running on lainchan.org
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

10 роки тому
10 роки тому
9 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
9 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
10 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. <?php
  2. require 'inc/lib/IP/Lifo/IP/IP.php';
  3. require 'inc/lib/IP/Lifo/IP/BC.php';
  4. require 'inc/lib/IP/Lifo/IP/CIDR.php';
  5. use Lifo\IP\CIDR;
  6. class Bans {
  7. static public function range_to_string($mask) {
  8. list($ipstart, $ipend) = $mask;
  9. if (!isset($ipend) || $ipend === false) {
  10. // Not a range. Single IP address.
  11. $ipstr = inet_ntop($ipstart);
  12. return $ipstr;
  13. }
  14. if (strlen($ipstart) != strlen($ipend))
  15. return '???'; // What the fuck are you doing, son?
  16. $range = CIDR::range_to_cidr(inet_ntop($ipstart), inet_ntop($ipend));
  17. if ($range !== false)
  18. return $range;
  19. return '???';
  20. }
  21. private static function calc_cidr($mask) {
  22. $cidr = new CIDR($mask);
  23. $range = $cidr->getRange();
  24. return array(inet_pton($range[0]), inet_pton($range[1]));
  25. }
  26. public static function parse_time($str) {
  27. if (empty($str))
  28. return false;
  29. if (($time = @strtotime($str)) !== false)
  30. return $time;
  31. if (!preg_match('/^((\d+)\s?ye?a?r?s?)?\s?+((\d+)\s?mon?t?h?s?)?\s?+((\d+)\s?we?e?k?s?)?\s?+((\d+)\s?da?y?s?)?((\d+)\s?ho?u?r?s?)?\s?+((\d+)\s?mi?n?u?t?e?s?)?\s?+((\d+)\s?se?c?o?n?d?s?)?$/', $str, $matches))
  32. return false;
  33. $expire = 0;
  34. if (isset($matches[2])) {
  35. // Years
  36. $expire += $matches[2]*60*60*24*365;
  37. }
  38. if (isset($matches[4])) {
  39. // Months
  40. $expire += $matches[4]*60*60*24*30;
  41. }
  42. if (isset($matches[6])) {
  43. // Weeks
  44. $expire += $matches[6]*60*60*24*7;
  45. }
  46. if (isset($matches[8])) {
  47. // Days
  48. $expire += $matches[8]*60*60*24;
  49. }
  50. if (isset($matches[10])) {
  51. // Hours
  52. $expire += $matches[10]*60*60;
  53. }
  54. if (isset($matches[12])) {
  55. // Minutes
  56. $expire += $matches[12]*60;
  57. }
  58. if (isset($matches[14])) {
  59. // Seconds
  60. $expire += $matches[14];
  61. }
  62. return time() + $expire;
  63. }
  64. static public function parse_range($mask) {
  65. $ipstart = false;
  66. $ipend = false;
  67. if (preg_match('@^(\d{1,3}\.){1,3}([\d*]{1,3})?$@', $mask) && substr_count($mask, '*') == 1) {
  68. // IPv4 wildcard mask
  69. $parts = explode('.', $mask);
  70. $ipv4 = '';
  71. foreach ($parts as $part) {
  72. if ($part == '*') {
  73. $ipstart = inet_pton($ipv4 . '0' . str_repeat('.0', 3 - substr_count($ipv4, '.')));
  74. $ipend = inet_pton($ipv4 . '255' . str_repeat('.255', 3 - substr_count($ipv4, '.')));
  75. break;
  76. } elseif(($wc = strpos($part, '*')) !== false) {
  77. $ipstart = inet_pton($ipv4 . substr($part, 0, $wc) . '0' . str_repeat('.0', 3 - substr_count($ipv4, '.')));
  78. $ipend = inet_pton($ipv4 . substr($part, 0, $wc) . '9' . str_repeat('.255', 3 - substr_count($ipv4, '.')));
  79. break;
  80. }
  81. $ipv4 .= "$part.";
  82. }
  83. } elseif (preg_match('@^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/\d+$@', $mask)) {
  84. list($ipv4, $bits) = explode('/', $mask);
  85. if ($bits > 32)
  86. return false;
  87. list($ipstart, $ipend) = self::calc_cidr($mask);
  88. } elseif (preg_match('@^[:a-z\d]+/\d+$@i', $mask)) {
  89. list($ipv6, $bits) = explode('/', $mask);
  90. if ($bits > 128)
  91. return false;
  92. list($ipstart, $ipend) = self::calc_cidr($mask);
  93. } else {
  94. if (($ipstart = @inet_pton($mask)) === false)
  95. return false;
  96. }
  97. return array($ipstart, $ipend);
  98. }
  99. static public function find($ip, $board = false, $get_mod_info = false) {
  100. global $config;
  101. $query = prepare('SELECT ``bans``.*' . ($get_mod_info ? ', `username`' : '') . ' FROM ``bans``
  102. ' . ($get_mod_info ? 'LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`' : '') . '
  103. WHERE
  104. (' . ($board !== false ? '(`board` IS NULL OR `board` = :board) AND' : '') . '
  105. (`ipstart` = :ip OR (:ip >= `ipstart` AND :ip <= `ipend`)))
  106. ORDER BY `expires` IS NULL, `expires` DESC');
  107. if ($board !== false)
  108. $query->bindValue(':board', $board, PDO::PARAM_STR);
  109. $query->bindValue(':ip', inet_pton($ip));
  110. $query->execute() or error(db_error($query));
  111. $ban_list = array();
  112. while ($ban = $query->fetch(PDO::FETCH_ASSOC)) {
  113. if ($ban['expires'] && ($ban['seen'] || !$config['require_ban_view']) && $ban['expires'] < time()) {
  114. self::delete($ban['id']);
  115. } else {
  116. if ($ban['post'])
  117. $ban['post'] = json_decode($ban['post'], true);
  118. $ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
  119. $ban_list[] = $ban;
  120. }
  121. }
  122. return $ban_list;
  123. }
  124. static public function stream_json($out = false, $filter_ips = false, $filter_staff = false, $board_access = false, $hide_regexes = []) {
  125. $query = query("SELECT ``bans``.*, `username` FROM ``bans``
  126. LEFT JOIN ``mods`` ON ``mods``.`id` = `creator`
  127. ORDER BY `created` DESC") or error(db_error());
  128. $bans = $query->fetchAll(PDO::FETCH_ASSOC);
  129. if ($board_access && $board_access[0] == '*') $board_access = false;
  130. $out ? fputs($out, "[") : print("[");
  131. $end = end($bans);
  132. foreach ($bans as &$ban) {
  133. $ban['mask'] = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
  134. $hide_message = false;
  135. foreach ($hide_regexes as $regex) {
  136. if(preg_match($regex, $ban['reason'])) {
  137. $hide_message = true;
  138. break;
  139. }
  140. }
  141. if ($ban['post'] && !$hide_message) {
  142. $post = json_decode($ban['post']);
  143. $ban['message'] = isset($post->body) ? $post->body : 0;
  144. }
  145. unset($ban['ipstart'], $ban['ipend'], $ban['post'], $ban['creator']);
  146. if ($board_access === false || in_array ($ban['board'], $board_access)) {
  147. $ban['access'] = true;
  148. }
  149. if (filter_var($ban['mask'], FILTER_VALIDATE_IP) !== false) {
  150. $ban['single_addr'] = true;
  151. }
  152. if ($filter_staff || ($board_access !== false && !in_array($ban['board'], $board_access))) {
  153. $ban['username'] = '?';
  154. }
  155. if ($filter_ips || ($board_access !== false && !in_array($ban['board'], $board_access))) {
  156. @list($ban['mask'], $subnet) = explode("/", $ban['mask']);
  157. $ban['mask'] = preg_split("/[\.:]/", $ban['mask']);
  158. $ban['mask'] = array_slice($ban['mask'], 0, 2);
  159. $ban['mask'] = implode(".", $ban['mask']);
  160. $ban['mask'] .= ".x.x";
  161. if (isset ($subnet)) {
  162. $ban['mask'] .= "/$subnet";
  163. }
  164. $ban['masked'] = true;
  165. }
  166. $json = json_encode($ban);
  167. $out ? fputs($out, $json) : print($json);
  168. if ($ban['id'] != $end['id']) {
  169. $out ? fputs($out, ",") : print(",");
  170. }
  171. }
  172. $out ? fputs($out, "]") : print("]");
  173. }
  174. static public function seen($ban_id) {
  175. $query = query("UPDATE ``bans`` SET `seen` = 1 WHERE `id` = " . (int)$ban_id) or error(db_error());
  176. rebuildThemes('bans');
  177. }
  178. static public function purge() {
  179. $query = query("DELETE FROM ``bans`` WHERE `expires` IS NOT NULL AND `expires` < " . time() . " AND `seen` = 1") or error(db_error());
  180. rebuildThemes('bans');
  181. }
  182. static public function delete($ban_id, $modlog = false, $boards = false, $dont_rebuild = false) {
  183. global $config;
  184. if ($boards && $boards[0] == '*') $boards = false;
  185. if ($modlog) {
  186. $query = query("SELECT `ipstart`, `ipend`, `board` FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
  187. if (!$ban = $query->fetch(PDO::FETCH_ASSOC)) {
  188. // Ban doesn't exist
  189. return false;
  190. }
  191. if ($boards !== false && !in_array($ban['board'], $boards))
  192. error($config['error']['noaccess']);
  193. $mask = self::range_to_string(array($ban['ipstart'], $ban['ipend']));
  194. modLog("Removed ban #{$ban_id} for " .
  195. (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : $mask));
  196. }
  197. query("DELETE FROM ``bans`` WHERE `id` = " . (int)$ban_id) or error(db_error());
  198. if (!$dont_rebuild) rebuildThemes('bans');
  199. return true;
  200. }
  201. static public function new_ban($mask, $reason, $length = false, $ban_board = false, $mod_id = false, $post = false) {
  202. global $mod, $pdo, $board;
  203. if ($mod_id === false) {
  204. $mod_id = isset($mod['id']) ? $mod['id'] : -1;
  205. }
  206. $range = self::parse_range($mask);
  207. $mask = self::range_to_string($range);
  208. $query = prepare("INSERT INTO ``bans`` VALUES (NULL, :ipstart, :ipend, :time, :expires, :board, :mod, :reason, 0, :post)");
  209. $query->bindValue(':ipstart', $range[0]);
  210. if ($range[1] !== false && $range[1] != $range[0])
  211. $query->bindValue(':ipend', $range[1]);
  212. else
  213. $query->bindValue(':ipend', null, PDO::PARAM_NULL);
  214. $query->bindValue(':mod', $mod_id);
  215. $query->bindValue(':time', time());
  216. if ($reason !== '') {
  217. $reason = escape_markup_modifiers($reason);
  218. markup($reason);
  219. $query->bindValue(':reason', $reason);
  220. } else
  221. $query->bindValue(':reason', null, PDO::PARAM_NULL);
  222. if ($length) {
  223. if (is_int($length) || ctype_digit($length)) {
  224. $length = time() + $length;
  225. } else {
  226. $length = self::parse_time($length);
  227. }
  228. $query->bindValue(':expires', $length);
  229. } else {
  230. $query->bindValue(':expires', null, PDO::PARAM_NULL);
  231. }
  232. if ($ban_board)
  233. $query->bindValue(':board', $ban_board);
  234. else
  235. $query->bindValue(':board', null, PDO::PARAM_NULL);
  236. if ($post) {
  237. $post['board'] = $board['uri'];
  238. $query->bindValue(':post', json_encode($post));
  239. } else
  240. $query->bindValue(':post', null, PDO::PARAM_NULL);
  241. $query->execute() or error(db_error($query));
  242. if (isset($mod['id']) && $mod['id'] == $mod_id) {
  243. modLog('Created a new ' .
  244. ($length > 0 ? preg_replace('/^(\d+) (\w+?)s?$/', '$1-$2', until($length)) : 'permanent') .
  245. ' ban on ' .
  246. ($ban_board ? '/' . $ban_board . '/' : 'all boards') .
  247. ' for ' .
  248. (filter_var($mask, FILTER_VALIDATE_IP) !== false ? "<a href=\"?/IP/$mask\">$mask</a>" : $mask) .
  249. ' (<small>#' . $pdo->lastInsertId() . '</small>)' .
  250. ' with ' . ($reason ? 'reason: ' . utf8tohtml($reason) . '' : 'no reason'));
  251. }
  252. rebuildThemes('bans');
  253. return $pdo->lastInsertId();
  254. }
  255. }