A bunch of half implemented shit, also r20160207
This commit is contained in:
parent
58776ee047
commit
ed00e852d8
17 changed files with 250 additions and 330 deletions
|
@ -1,14 +0,0 @@
|
||||||
103.21.244.0/22
|
|
||||||
103.22.200.0/22
|
|
||||||
103.31.4.0/22
|
|
||||||
104.16.0.0/12
|
|
||||||
108.162.192.0/18
|
|
||||||
141.101.64.0/18
|
|
||||||
162.158.0.0/15
|
|
||||||
172.64.0.0/13
|
|
||||||
173.245.48.0/20
|
|
||||||
188.114.96.0/20
|
|
||||||
190.93.240.0/20
|
|
||||||
197.234.240.0/22
|
|
||||||
198.41.128.0/17
|
|
||||||
199.27.128.0/21
|
|
|
@ -1,5 +0,0 @@
|
||||||
2400:cb00::/32
|
|
||||||
2405:8100::/32
|
|
||||||
2405:b500::/32
|
|
||||||
2606:4700::/32
|
|
||||||
2803:f800::/32
|
|
|
@ -33,12 +33,6 @@ prefix = sakura_
|
||||||
|
|
||||||
; Data files relative to the root directory
|
; Data files relative to the root directory
|
||||||
[data]
|
[data]
|
||||||
; File containing CloudFlare IPv4 CIDRs
|
|
||||||
cfipv4 = config/cloudflare.ipv4
|
|
||||||
|
|
||||||
; File containing CloudFlare IPv6 CIDRs
|
|
||||||
cfipv6 = config/cloudflare.ipv6
|
|
||||||
|
|
||||||
; JSON file containing WHOIS servers
|
; JSON file containing WHOIS servers
|
||||||
whoisservers = config/whois.json
|
whoisservers = config/whois.json
|
||||||
|
|
||||||
|
|
|
@ -91,7 +91,7 @@ class Meta
|
||||||
Template::vars([
|
Template::vars([
|
||||||
'page' => [
|
'page' => [
|
||||||
'title' => 'Frequently Asked Questions',
|
'title' => 'Frequently Asked Questions',
|
||||||
'questions' => Utils::getFaqData(),
|
'questions' => Database::fetch('faq', true, null, ['faq_id']),
|
||||||
],
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -117,7 +117,7 @@ class Meta
|
||||||
$id = strtolower($id);
|
$id = strtolower($id);
|
||||||
|
|
||||||
// Get info page data from the database
|
// Get info page data from the database
|
||||||
if ($ipData = Utils::loadInfoPage($id)) {
|
if ($ipData = Database::fetch('infopages', false, ['page_shorthand' => [$id, '=']])) {
|
||||||
// Assign new proper variable
|
// Assign new proper variable
|
||||||
$renderData['page'] = [
|
$renderData['page'] = [
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Sakura\Database;
|
||||||
use Sakura\User;
|
use Sakura\User;
|
||||||
use Sakura\BBcode;
|
use Sakura\BBcode;
|
||||||
use Sakura\Config;
|
use Sakura\Config;
|
||||||
|
use Sakura\Net;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to serve, create and update posts.
|
* Used to serve, create and update posts.
|
||||||
|
@ -212,7 +213,7 @@ class Post
|
||||||
'topic_id' => $thread->id,
|
'topic_id' => $thread->id,
|
||||||
'forum_id' => $thread->forum,
|
'forum_id' => $thread->forum,
|
||||||
'poster_id' => $this->poster->id,
|
'poster_id' => $this->poster->id,
|
||||||
'poster_ip' => Utils::getRemoteIP(),
|
'poster_ip' => Net::pton(Net::IP()),
|
||||||
'post_time' => $this->time,
|
'post_time' => $this->time,
|
||||||
'post_subject' => $this->subject,
|
'post_subject' => $this->subject,
|
||||||
'post_text' => $this->text,
|
'post_text' => $this->text,
|
||||||
|
|
212
libraries/Net.php
Normal file
212
libraries/Net.php
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Holds the everything networking.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Sakura;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Networking methods.
|
||||||
|
*
|
||||||
|
* @package Sakura
|
||||||
|
* @author Julian van de Groep <me@flash.moe>
|
||||||
|
*/
|
||||||
|
class Net {
|
||||||
|
/**
|
||||||
|
* Returns the connecting IP.
|
||||||
|
*
|
||||||
|
* @return string The IP.
|
||||||
|
*/
|
||||||
|
public static function IP()
|
||||||
|
{
|
||||||
|
return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '::1';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect the version of an IP.
|
||||||
|
*
|
||||||
|
* @param string $ipAddr The IP.
|
||||||
|
*
|
||||||
|
* @return int Either 0, 4 or 6.
|
||||||
|
*/
|
||||||
|
public static function detectIPVersion($ipAddr)
|
||||||
|
{
|
||||||
|
// Check if var is IP
|
||||||
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP)) {
|
||||||
|
// v4
|
||||||
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// v6
|
||||||
|
if (filter_var($ipAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
||||||
|
return 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not an IP or unknown type
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a printable IP address into an unpacked binary string.
|
||||||
|
*
|
||||||
|
* @param string $ip Printable IP string.
|
||||||
|
*
|
||||||
|
* @throws \Exception Thrown if an invalid IP is supplied.
|
||||||
|
*
|
||||||
|
* @return string Unpacked IP address.
|
||||||
|
*/
|
||||||
|
public static function pton($ip)
|
||||||
|
{
|
||||||
|
// Detect the IP version
|
||||||
|
$ipv = self::detectIPVersion($ip);
|
||||||
|
|
||||||
|
// Check for IPv4 first since that's most common
|
||||||
|
if ($ipv === 4) {
|
||||||
|
return current(unpack("A4", inet_pton($ip)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then attempt IPv6
|
||||||
|
if ($ipv === 6) {
|
||||||
|
return current(unpack("A16", inet_pton($ip)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Throw an exception if an invalid IP was supplied
|
||||||
|
throw new \Exception("Invalid IP address supplied.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a binary unpacked IP to a printable packed IP.
|
||||||
|
*
|
||||||
|
* @param string $bin The unpacked IP.
|
||||||
|
*
|
||||||
|
* @throws \Exception Thrown if the unpacked IP is invalid.
|
||||||
|
*
|
||||||
|
* @return string The packed IP.
|
||||||
|
*/
|
||||||
|
public static function ntop($bin)
|
||||||
|
{
|
||||||
|
// Get the length of the binary string
|
||||||
|
$len = strlen($bin);
|
||||||
|
|
||||||
|
// Throw an exception if it's not 4 or 16 bytes
|
||||||
|
if ($len !== 4 && $len !== 16) {
|
||||||
|
throw new \Exception("Could not handle this IP type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally pack the IP
|
||||||
|
return inet_ntop(pack("A{$len}", $bin));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function matchCIDR($ip, $range)
|
||||||
|
{
|
||||||
|
// Break the range up in parts
|
||||||
|
list($net, $mask) = explode('/', $range);
|
||||||
|
|
||||||
|
// Check IP version
|
||||||
|
$ipv = self::detectIPVersion($ip);
|
||||||
|
$rangev = self::detectIPVersion($net);
|
||||||
|
|
||||||
|
// Return false if it's not a valid IP
|
||||||
|
if ($ipv !== $rangev && !$ipv) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// v4
|
||||||
|
if ($ipv === 4) {
|
||||||
|
return self::matchCIDRv4($ip, $net, $mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// v6
|
||||||
|
if ($ipv === 6) {
|
||||||
|
return self::matchCIDRv6($ip, $net, $mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return false by default
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match an IPv4 CIDR
|
||||||
|
*
|
||||||
|
* @param string $ip The IP address to match.
|
||||||
|
* @param string $net The Net address to match.
|
||||||
|
* @param string $mask The Mask to match.
|
||||||
|
*
|
||||||
|
* @return bool Returns true if it matches.
|
||||||
|
*/
|
||||||
|
private static function matchCIDRv4($ip, $net, $mask)
|
||||||
|
{
|
||||||
|
// Convert IP and Net address to long
|
||||||
|
$ip = ip2long($ip);
|
||||||
|
$net = ip2long($net);
|
||||||
|
|
||||||
|
// Generate mask
|
||||||
|
$mask = -1 << (32 - $mask);
|
||||||
|
|
||||||
|
// Do the check
|
||||||
|
return ($ip & $mask) === $net;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an IPv6 mask to a byte array
|
||||||
|
*
|
||||||
|
* @param int $mask The mask.
|
||||||
|
*
|
||||||
|
* @return string The byte array.
|
||||||
|
*/
|
||||||
|
private static function maskToByteArray($mask)
|
||||||
|
{
|
||||||
|
// Generate an address from the mask
|
||||||
|
$addr = str_repeat("f", $mask / 4);
|
||||||
|
|
||||||
|
// Append uneven bit
|
||||||
|
switch ($mask % 4) {
|
||||||
|
case 1:
|
||||||
|
$addr .= '8';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
$addr .= 'c';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
$addr .= 'e';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pad the address with zeroes
|
||||||
|
$addr = str_pad($addr, 32, '0');
|
||||||
|
|
||||||
|
// Pack the address
|
||||||
|
$addr = pack('H*', $addr);
|
||||||
|
|
||||||
|
// Return the packed address
|
||||||
|
return $addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match an IPv6 CIDR
|
||||||
|
*
|
||||||
|
* @param string $ip The IP address to match.
|
||||||
|
* @param string $net The Net address to match.
|
||||||
|
* @param int $mask The net mask.
|
||||||
|
*
|
||||||
|
* @return bool Returns true if it's a successful match.
|
||||||
|
*/
|
||||||
|
private static function matchCIDRv6($ip, $net, $mask)
|
||||||
|
{
|
||||||
|
// Pack the IP and Net addresses
|
||||||
|
$ip = inet_pton($ip);
|
||||||
|
$net = inet_pton($net);
|
||||||
|
|
||||||
|
// Convert the mask to a byte array
|
||||||
|
$mask = self::maskToByteArray($mask);
|
||||||
|
|
||||||
|
// Compare them
|
||||||
|
return ($ip & $mask) === $net;
|
||||||
|
}
|
||||||
|
}
|
|
@ -145,8 +145,10 @@ class Router
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
return self::$dispatcher->dispatch($method, $url);
|
return self::$dispatcher->dispatch($method, $url);
|
||||||
} catch (HttpMethodNotAllowedException $e) {}
|
} catch (HttpMethodNotAllowedException $e) {
|
||||||
} catch (HttpRouteNotFoundException $e) {}
|
}
|
||||||
|
} catch (HttpRouteNotFoundException $e) {
|
||||||
|
}
|
||||||
|
|
||||||
// Default to the not found page
|
// Default to the not found page
|
||||||
return Template::render('global/notfound');
|
return Template::render('global/notfound');
|
||||||
|
|
|
@ -95,7 +95,7 @@ class Session
|
||||||
// Insert the session into the database
|
// Insert the session into the database
|
||||||
Database::insert('sessions', [
|
Database::insert('sessions', [
|
||||||
'user_id' => $this->userId,
|
'user_id' => $this->userId,
|
||||||
'user_ip' => Utils::getRemoteIP(),
|
'user_ip' => Net::pton(Net::IP()),
|
||||||
'user_agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'),
|
'user_agent' => Utils::cleanString(isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : 'No user agent header.'),
|
||||||
'session_key' => $session,
|
'session_key' => $session,
|
||||||
'session_start' => time(),
|
'session_start' => time(),
|
||||||
|
@ -132,13 +132,13 @@ class Session
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP Check
|
// IP Check
|
||||||
$ipCheck = Config::get('session_check');
|
$ipCheck = false;// Config::get('session_check');
|
||||||
|
|
||||||
// Origin checking
|
// Origin checking
|
||||||
if ($ipCheck) {
|
if ($ipCheck) {
|
||||||
// Split both IPs up
|
// Split both IPs up
|
||||||
$sessionIP = explode('.', $session['user_ip']);
|
$sessionIP = explode('.', $session['user_ip']);
|
||||||
$userIP = explode('.', Utils::getRemoteIP());
|
$userIP = explode('.', Net::IP());
|
||||||
|
|
||||||
// Take 1 off the ipCheck variable so it's equal to the array keys
|
// Take 1 off the ipCheck variable so it's equal to the array keys
|
||||||
$ipCheck = $ipCheck - 1;
|
$ipCheck = $ipCheck - 1;
|
||||||
|
|
|
@ -267,8 +267,8 @@ class User
|
||||||
'password_iter' => $password[1],
|
'password_iter' => $password[1],
|
||||||
'email' => $emailClean,
|
'email' => $emailClean,
|
||||||
'rank_main' => 0,
|
'rank_main' => 0,
|
||||||
'register_ip' => Utils::getRemoteIP(),
|
'register_ip' => Net::pton(Net::IP()),
|
||||||
'last_ip' => Utils::getRemoteIP(),
|
'last_ip' => Net::pton(Net::IP()),
|
||||||
'user_registered' => time(),
|
'user_registered' => time(),
|
||||||
'user_last_online' => 0,
|
'user_last_online' => 0,
|
||||||
'user_country' => Utils::getCountryCode(),
|
'user_country' => Utils::getCountryCode(),
|
||||||
|
|
|
@ -120,7 +120,7 @@ class Users
|
||||||
|
|
||||||
// Check if we haven't hit the rate limit
|
// Check if we haven't hit the rate limit
|
||||||
$rates = Database::fetch('login_attempts', true, [
|
$rates = Database::fetch('login_attempts', true, [
|
||||||
'attempt_ip' => [Utils::getRemoteIP(), '='],
|
'attempt_ip' => [Net::pton(Net::IP()), '='],
|
||||||
'attempt_timestamp' => [time() - 1800, '>'],
|
'attempt_timestamp' => [time() - 1800, '>'],
|
||||||
'attempt_success' => [0, '='],
|
'attempt_success' => [0, '='],
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -17,16 +17,6 @@ use PHPMailer;
|
||||||
*/
|
*/
|
||||||
class Utils
|
class Utils
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Get the emoticons.
|
|
||||||
*
|
|
||||||
* @return array Array containing emoticons.
|
|
||||||
*/
|
|
||||||
public static function getEmotes()
|
|
||||||
{
|
|
||||||
return Database::fetch('emoticons');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the emoticons.
|
* Parse the emoticons.
|
||||||
*
|
*
|
||||||
|
@ -36,9 +26,8 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function parseEmotes($text)
|
public static function parseEmotes($text)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Get emoticons from the database
|
// Get emoticons from the database
|
||||||
$emotes = self::getEmotes();
|
$emotes = Database::fetch('emoticons');
|
||||||
|
|
||||||
// Do the replacements
|
// Do the replacements
|
||||||
foreach ($emotes as $emote) {
|
foreach ($emotes as $emote) {
|
||||||
|
@ -62,7 +51,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function verifyCaptcha($response)
|
public static function verifyCaptcha($response)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Attempt to get the response
|
// Attempt to get the response
|
||||||
$resp = @file_get_contents(
|
$resp = @file_get_contents(
|
||||||
'https://www.google.com/recaptcha/api/siteverify?secret='
|
'https://www.google.com/recaptcha/api/siteverify?secret='
|
||||||
|
@ -93,7 +81,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function errorHandler($errno, $errstr, $errfile, $errline)
|
public static function errorHandler($errno, $errstr, $errfile, $errline)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Remove ROOT path from the error string and file location
|
// Remove ROOT path from the error string and file location
|
||||||
$errstr = str_replace(ROOT, '', $errstr);
|
$errstr = str_replace(ROOT, '', $errstr);
|
||||||
$errfile = str_replace(ROOT, '', $errfile);
|
$errfile = str_replace(ROOT, '', $errfile);
|
||||||
|
@ -254,7 +241,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function sendMail($to, $subject, $body)
|
public static function sendMail($to, $subject, $body)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Initialise PHPMailer
|
// Initialise PHPMailer
|
||||||
$mail = new PHPMailer();
|
$mail = new PHPMailer();
|
||||||
|
|
||||||
|
@ -323,7 +309,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function cleanString($string, $lower = false, $noSpecial = false, $replaceSpecial = '')
|
public static function cleanString($string, $lower = false, $noSpecial = false, $replaceSpecial = '')
|
||||||
{
|
{
|
||||||
|
|
||||||
// Run common sanitisation function over string
|
// Run common sanitisation function over string
|
||||||
$string = htmlentities($string, ENT_NOQUOTES | ENT_HTML401, Config::get('charset'));
|
$string = htmlentities($string, ENT_NOQUOTES | ENT_HTML401, Config::get('charset'));
|
||||||
$string = stripslashes($string);
|
$string = stripslashes($string);
|
||||||
|
@ -343,23 +328,6 @@ class Utils
|
||||||
return $string;
|
return $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load contents of an infopage.
|
|
||||||
*
|
|
||||||
* @param string $id ID of the info page.
|
|
||||||
*
|
|
||||||
* @return array|bool Contents of the info page.
|
|
||||||
*/
|
|
||||||
public static function loadInfoPage($id)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Get contents from the database
|
|
||||||
$infopage = Database::fetch('infopages', false, ['page_shorthand' => [$id, '=']]);
|
|
||||||
|
|
||||||
// Return the data if there is any else just return false
|
|
||||||
return count($infopage) ? $infopage : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate MX records.
|
* Validate MX records.
|
||||||
*
|
*
|
||||||
|
@ -369,7 +337,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function checkMXRecord($email)
|
public static function checkMXRecord($email)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Get the domain from the e-mail address
|
// Get the domain from the e-mail address
|
||||||
$domain = substr(strstr($email, '@'), 1);
|
$domain = substr(strstr($email, '@'), 1);
|
||||||
|
|
||||||
|
@ -380,174 +347,6 @@ class Utils
|
||||||
return $record;
|
return $record;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect the version of an IP.
|
|
||||||
*
|
|
||||||
* @param string $ip The IP.
|
|
||||||
*
|
|
||||||
* @return int Either 0, 4 or 6.
|
|
||||||
*/
|
|
||||||
public static function ipVersion($ip)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Check if var is IP
|
|
||||||
if (filter_var($ip, FILTER_VALIDATE_IP)) {
|
|
||||||
// IPv4
|
|
||||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// IPv6
|
|
||||||
if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Not an IP or unknown type
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpack an IPv6
|
|
||||||
*
|
|
||||||
* @param mixed $inet IP address.
|
|
||||||
*
|
|
||||||
* @return null|string The unpacked IP.
|
|
||||||
*/
|
|
||||||
public static function inetToBits($inet)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Unpack string
|
|
||||||
$unpacked = unpack('A16', $inet);
|
|
||||||
|
|
||||||
// Split the string
|
|
||||||
$unpacked = str_split($unpacked[1]);
|
|
||||||
|
|
||||||
// Define variable
|
|
||||||
$binaryIP = null;
|
|
||||||
|
|
||||||
// "Build" binary IP
|
|
||||||
foreach ($unpacked as $char) {
|
|
||||||
$binaryIP .= str_pad(decbin(ord($char)), 8, '0', STR_PAD_LEFT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return IP
|
|
||||||
return $binaryIP;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match a subnet.
|
|
||||||
*
|
|
||||||
* @param string $ip the IP.
|
|
||||||
* @param string $range The range.
|
|
||||||
*
|
|
||||||
* @return bool|int Success.
|
|
||||||
*/
|
|
||||||
public static function matchSubnet($ip, $range)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Use the proper IP type
|
|
||||||
switch (self::ipVersion($ip)) {
|
|
||||||
case 4:
|
|
||||||
// Break the range up in parts
|
|
||||||
list($subnet, $bits) = explode('/', $range);
|
|
||||||
|
|
||||||
// Convert IP and Subnet to long
|
|
||||||
$ip = ip2long($ip);
|
|
||||||
$subnet = ip2long($subnet);
|
|
||||||
$mask = -1 << (32 - $bits);
|
|
||||||
|
|
||||||
// In case the supplied subnet wasn't correctly aligned
|
|
||||||
$subnet &= $mask;
|
|
||||||
|
|
||||||
// Return true if IP is in subnet
|
|
||||||
return ($ip & $mask) == $subnet;
|
|
||||||
|
|
||||||
case 6:
|
|
||||||
// Break the range up in parts
|
|
||||||
list($subnet, $bits) = explode('/', $range);
|
|
||||||
|
|
||||||
// Convert subnet to packed address and convert it to binary
|
|
||||||
$subnet = inet_pton($subnet);
|
|
||||||
$binarySubnet = self::inetToBits($subnet);
|
|
||||||
|
|
||||||
// Convert IPv6 to packed address and convert it to binary as well
|
|
||||||
$ip = inet_pton($ip);
|
|
||||||
$binaryIP = self::inetToBits($ip);
|
|
||||||
|
|
||||||
// Return bits of the strings according to the bits
|
|
||||||
$ipBits = substr($binaryIP, 0, $bits);
|
|
||||||
$subnetBits = substr($binarySubnet, 0, $bits);
|
|
||||||
|
|
||||||
return ($ipBits === $subnetBits);
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if an IP originates from CloudFlare.
|
|
||||||
*
|
|
||||||
* @param string $ip The IP.
|
|
||||||
*
|
|
||||||
* @return bool Success.
|
|
||||||
*/
|
|
||||||
public static function checkCFIP($ip)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Get CloudFlare Subnet list
|
|
||||||
$cfhosts = file_get_contents(
|
|
||||||
ROOT . Config::local('data', 'cfipv' . (self::ipVersion($ip)))
|
|
||||||
);
|
|
||||||
|
|
||||||
// Replace \r\n with \n
|
|
||||||
$cfhosts = str_replace("\r\n", "\n", $cfhosts);
|
|
||||||
|
|
||||||
// Explode the file into an array
|
|
||||||
$cfhosts = explode("\n", $cfhosts);
|
|
||||||
|
|
||||||
// Check if IP is in a CloudFlare subnet
|
|
||||||
foreach ($cfhosts as $subnet) {
|
|
||||||
// Check if the subnet isn't empty (git newline prevention)
|
|
||||||
if (strlen($subnet) < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return true if found
|
|
||||||
if (self::matchSubnet($ip, $subnet)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return false if fails
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the IP of a visitor.
|
|
||||||
*
|
|
||||||
* @return string The IP.
|
|
||||||
*/
|
|
||||||
public static function getRemoteIP()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Assign REMOTE_ADDR to a variables
|
|
||||||
$ip = $_SERVER['REMOTE_ADDR'];
|
|
||||||
|
|
||||||
// Check if the IP is a CloudFlare IP
|
|
||||||
if (self::checkCFIP($ip)) {
|
|
||||||
// If it is check if the CloudFlare IP header is set and if it is assign it to the ip variable
|
|
||||||
if (isset($_SERVER['HTTP_CF_CONNECTING_IP'])) {
|
|
||||||
$ip = $_SERVER['HTTP_CF_CONNECTING_IP'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the correct IP
|
|
||||||
return $ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the country code of a visitor.
|
* Get the country code of a visitor.
|
||||||
*
|
*
|
||||||
|
@ -557,7 +356,7 @@ class Utils
|
||||||
{
|
{
|
||||||
// Attempt to get country code using PHP's built in geo thing
|
// Attempt to get country code using PHP's built in geo thing
|
||||||
if (function_exists("geoip_country_code_by_name")) {
|
if (function_exists("geoip_country_code_by_name")) {
|
||||||
$code = geoip_country_code_by_name(self::getRemoteIP());
|
$code = geoip_country_code_by_name(Net::IP());
|
||||||
|
|
||||||
// Check if $code is anything
|
// Check if $code is anything
|
||||||
if ($code) {
|
if ($code) {
|
||||||
|
@ -583,7 +382,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function pwdEntropy($pw)
|
public static function pwdEntropy($pw)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Decode utf-8 chars
|
// Decode utf-8 chars
|
||||||
$pw = utf8_decode($pw);
|
$pw = utf8_decode($pw);
|
||||||
|
|
||||||
|
@ -600,7 +398,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function getCountryName($code)
|
public static function getCountryName($code)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Parse JSON file
|
// Parse JSON file
|
||||||
$iso3166 = json_decode(
|
$iso3166 = json_decode(
|
||||||
utf8_encode(
|
utf8_encode(
|
||||||
|
@ -620,72 +417,6 @@ class Utils
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the FAQ table data (why is this a function).
|
|
||||||
*
|
|
||||||
* @return array FAQ data.
|
|
||||||
*/
|
|
||||||
public static function getFaqData()
|
|
||||||
{
|
|
||||||
|
|
||||||
// Do database call
|
|
||||||
$faq = Database::fetch('faq', true, null, ['faq_id']);
|
|
||||||
|
|
||||||
// Return FAQ data
|
|
||||||
return $faq;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the type of log in text (unused and will probably be removwed).
|
|
||||||
* @param mixed $type
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public static function getLogStringFromType($type)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Query the database
|
|
||||||
$return = Database::fetch('logtypes', false, ['id' => [$type, '=']]);
|
|
||||||
|
|
||||||
// Check if type exists and else return a unformattable string
|
|
||||||
if (count($return) < 2) {
|
|
||||||
return 'Unknown action.';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return the string
|
|
||||||
return $return['string'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a user's logs (unused, probably removed in future).
|
|
||||||
* @param mixed $uid
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function getUserLogs($uid = 0)
|
|
||||||
{
|
|
||||||
|
|
||||||
// Check if a user is specified
|
|
||||||
$conditions = ($uid ? ['uid' => [$uid, '=']] : null);
|
|
||||||
|
|
||||||
// Get data from database
|
|
||||||
$logsDB = Database::fetch('logs', true, $conditions, ['id', true]);
|
|
||||||
|
|
||||||
// Storage array
|
|
||||||
$logs = [];
|
|
||||||
|
|
||||||
// Iterate over entries
|
|
||||||
foreach ($logsDB as $log) {
|
|
||||||
// Store usable data
|
|
||||||
$logs[$log['id']] = [
|
|
||||||
'user' => $_USER = Users::getUser($log['uid']),
|
|
||||||
'rank' => Users::getRank($_USER['rank_main']),
|
|
||||||
'string' => vsprintf(self::getLogStringFromType($log['action']), json_decode($log['attribs'], true)),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return new logs
|
|
||||||
return $logs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the byte symbol for a unit from bytes.
|
* Get the byte symbol for a unit from bytes.
|
||||||
*
|
*
|
||||||
|
@ -695,7 +426,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function getByteSymbol($bytes)
|
public static function getByteSymbol($bytes)
|
||||||
{
|
{
|
||||||
|
|
||||||
// Return nothing if the input was 0
|
// Return nothing if the input was 0
|
||||||
if (!$bytes) {
|
if (!$bytes) {
|
||||||
return;
|
return;
|
||||||
|
@ -721,7 +451,6 @@ class Utils
|
||||||
*/
|
*/
|
||||||
public static function getPremiumTrackerData()
|
public static function getPremiumTrackerData()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Create data array
|
// Create data array
|
||||||
$data = [];
|
$data = [];
|
||||||
|
|
||||||
|
@ -762,12 +491,10 @@ class Utils
|
||||||
public static function updatePremiumTracker($id, $amount, $comment)
|
public static function updatePremiumTracker($id, $amount, $comment)
|
||||||
{
|
{
|
||||||
Database::insert('premium_log', [
|
Database::insert('premium_log', [
|
||||||
|
|
||||||
'user_id' => $id,
|
'user_id' => $id,
|
||||||
'transaction_amount' => $amount,
|
'transaction_amount' => $amount,
|
||||||
'transaction_date' => time(),
|
'transaction_date' => time(),
|
||||||
'transaction_comment' => $comment,
|
'transaction_comment' => $comment,
|
||||||
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,7 +187,7 @@ if (isset($_REQUEST['mode'])) {
|
||||||
Database::insert('login_attempts', [
|
Database::insert('login_attempts', [
|
||||||
'attempt_success' => $login[0],
|
'attempt_success' => $login[0],
|
||||||
'attempt_timestamp' => time(),
|
'attempt_timestamp' => time(),
|
||||||
'attempt_ip' => Utils::getRemoteIP(),
|
'attempt_ip' => Net::pton(Net::IP()),
|
||||||
'user_id' => isset($login[2]) ? $login[2] : 0,
|
'user_id' => isset($login[2]) ? $login[2] : 0,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ if (Users::checkLogin()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if a user has already registered from the current IP address
|
// Check if a user has already registered from the current IP address
|
||||||
if (count($regUserIP = Users::getUsersByIP(Utils::getRemoteIP()))) {
|
if (count($regUserIP = Users::getUsersByIP(Net::pton(Net::IP())))) {
|
||||||
$renderData['auth']['blockRegister'] = [
|
$renderData['auth']['blockRegister'] = [
|
||||||
|
|
||||||
'do' => true,
|
'do' => true,
|
||||||
|
|
|
@ -118,12 +118,13 @@ var Sakura = (function () {
|
||||||
}
|
}
|
||||||
// Times array
|
// Times array
|
||||||
var times = {
|
var times = {
|
||||||
31536000: 'year',
|
31536000: ['year', 'a'],
|
||||||
2592000: 'month',
|
2592000: ['month', 'a'],
|
||||||
86400: 'day',
|
604800: ['week', 'a'],
|
||||||
3600: 'hour',
|
86400: ['day', 'a'],
|
||||||
60: 'minute',
|
3600: ['hour', 'an'],
|
||||||
1: 'second'
|
60: ['minute', 'a'],
|
||||||
|
1: ['second', 'a']
|
||||||
};
|
};
|
||||||
//
|
//
|
||||||
var timeKeys = Object.keys(times).reverse();
|
var timeKeys = Object.keys(times).reverse();
|
||||||
|
@ -136,7 +137,7 @@ var Sakura = (function () {
|
||||||
// Round the number
|
// Round the number
|
||||||
var display = Math.floor(calc);
|
var display = Math.floor(calc);
|
||||||
// Return the formatted string
|
// Return the formatted string
|
||||||
return display + " " + times[timeKeys[i]] + (display === 1 ? '' : 's') + append;
|
return (display === 1 ? times[timeKeys[i]][1] : display) + " " + times[timeKeys[i]][0] + (display === 1 ? '' : 's') + append;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If everything fails just return none
|
// If everything fails just return none
|
||||||
|
|
|
@ -141,12 +141,13 @@ class Sakura {
|
||||||
|
|
||||||
// Times array
|
// Times array
|
||||||
var times: Object = {
|
var times: Object = {
|
||||||
31536000: 'year',
|
31536000: ['year', 'a'],
|
||||||
2592000: 'month',
|
2592000: ['month', 'a'],
|
||||||
86400: 'day',
|
604800: ['week', 'a'],
|
||||||
3600: 'hour',
|
86400: ['day', 'a'],
|
||||||
60: 'minute',
|
3600: ['hour', 'an'],
|
||||||
1: 'second'
|
60: ['minute', 'a'],
|
||||||
|
1: ['second', 'a']
|
||||||
};
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -163,7 +164,7 @@ class Sakura {
|
||||||
var display: number = Math.floor(calc);
|
var display: number = Math.floor(calc);
|
||||||
|
|
||||||
// Return the formatted string
|
// Return the formatted string
|
||||||
return display + " " + times[timeKeys[i]] + (display === 1 ? '' : 's') + append;
|
return (display === 1 ? times[timeKeys[i]][1] : display) + " " + times[timeKeys[i]][0] + (display === 1 ? '' : 's') + append;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
namespace Sakura;
|
namespace Sakura;
|
||||||
|
|
||||||
// Include components
|
// Include components
|
||||||
require_once str_replace(basename(__DIR__), '', dirname(__FILE__)) . 'sakura.php';
|
require_once __DIR__ . '/../sakura.php';
|
||||||
|
|
||||||
// Handle requests
|
// Handle requests
|
||||||
echo Router::handle($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
echo Router::handle($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI']);
|
||||||
|
|
|
@ -69,7 +69,7 @@ $mode = isset($_GET['f']) ? 'f' : (isset($_GET['t']) ? 't' : (isset($_GET['p'])
|
||||||
|
|
||||||
// Include emotes and bbcodes
|
// Include emotes and bbcodes
|
||||||
$posting = [
|
$posting = [
|
||||||
'emoticons' => Utils::getEmotes(),
|
'emoticons' => Database::fetch('emoticons'),
|
||||||
];
|
];
|
||||||
|
|
||||||
// Check if we're in reply mode
|
// Check if we're in reply mode
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
namespace Sakura;
|
namespace Sakura;
|
||||||
|
|
||||||
// Define Sakura version
|
// Define Sakura version
|
||||||
define('SAKURA_VERSION', '20160205');
|
define('SAKURA_VERSION', '20160207');
|
||||||
define('SAKURA_VLABEL', 'Amethyst');
|
define('SAKURA_VLABEL', 'Amethyst');
|
||||||
define('SAKURA_COLOUR', '#9966CC');
|
define('SAKURA_COLOUR', '#9966CC');
|
||||||
|
|
||||||
|
@ -45,6 +45,7 @@ require_once ROOT . 'libraries/CSRF.php';
|
||||||
require_once ROOT . 'libraries/Database.php';
|
require_once ROOT . 'libraries/Database.php';
|
||||||
require_once ROOT . 'libraries/File.php';
|
require_once ROOT . 'libraries/File.php';
|
||||||
require_once ROOT . 'libraries/Hashing.php';
|
require_once ROOT . 'libraries/Hashing.php';
|
||||||
|
require_once ROOT . 'libraries/Net.php';
|
||||||
require_once ROOT . 'libraries/News.php';
|
require_once ROOT . 'libraries/News.php';
|
||||||
require_once ROOT . 'libraries/Payments.php';
|
require_once ROOT . 'libraries/Payments.php';
|
||||||
require_once ROOT . 'libraries/Perms.php';
|
require_once ROOT . 'libraries/Perms.php';
|
||||||
|
|
Reference in a new issue