From 0e094809fafce00668868d8babb9887451644869 Mon Sep 17 00:00:00 2001 From: Skylar Ittner Date: Fri, 14 Dec 2018 19:13:26 -0700 Subject: [PATCH] Cleanup some technical debt --- action.php | 2 +- api.php | 12 +-- app.php | 6 +- index.php | 4 +- lib/IPUtils.lib.php | 6 +- lib/Log.lib.php | 2 +- lib/User.lib.php | 8 +- mobile/index.php | 2 +- required.php | 204 +------------------------------------------- setup.php | 2 +- 10 files changed, 24 insertions(+), 224 deletions(-) diff --git a/action.php b/action.php index b11b97d..2ae31a8 100644 --- a/action.php +++ b/action.php @@ -70,7 +70,7 @@ switch ($VARS['action']) { returnToSender("new_pin_mismatch"); break; case "add2fa": - if (is_empty($VARS['secret'])) { + if (empty($VARS['secret'])) { returnToSender("invalid_parameters"); } $user = new User($_SESSION['uid']); diff --git a/api.php b/api.php index 90d2d7c..c8784ad 100644 --- a/api.php +++ b/api.php @@ -206,7 +206,7 @@ switch ($VARS['action']) { exit(json_encode(["status" => "OK", "managers" => $managers])); break; case "usersearch": - if (is_empty($VARS['search']) || strlen($VARS['search']) < 3) { + if (empty($VARS['search']) || strlen($VARS['search']) < 3) { exit(json_encode(["status" => "OK", "result" => []])); } $data = $database->select('accounts', ['uid', 'username', 'realname (name)'], ["OR" => ['username[~]' => $VARS['search'], 'realname[~]' => $VARS['search']], "LIMIT" => 10]); @@ -234,7 +234,7 @@ switch ($VARS['action']) { case "mobileenabled": exit(json_encode(["status" => "OK", "mobile" => MOBILE_ENABLED])); case "mobilevalid": - if (is_empty($VARS['username']) || is_empty($VARS['code'])) { + if (empty($VARS['username']) || empty($VARS['code'])) { http_response_code(400); die("\"400 Bad Request\""); } @@ -243,12 +243,12 @@ switch ($VARS['action']) { exit(json_encode(["status" => "OK", "valid" => $user_key_valid])); case "alertemail": engageRateLimit(); - if (is_empty($VARS['username']) || !User::byUsername($VARS['username'])->exists()) { + if (empty($VARS['username']) || !User::byUsername($VARS['username'])->exists()) { http_response_code(400); die("\"400 Bad Request\""); } $appname = "???"; - if (!is_empty($VARS['appname'])) { + if (!empty($VARS['appname'])) { $appname = $VARS['appname']; } $result = User::byUsername($VARS['username'])->sendAlertEmail($appname); @@ -325,7 +325,7 @@ switch ($VARS['action']) { exit(json_encode(["status" => "OK", "groups" => $groups])); break; case "groupsearch": - if (is_empty($VARS['search']) || strlen($VARS['search']) < 2) { + if (empty($VARS['search']) || strlen($VARS['search']) < 2) { exit(json_encode(["status" => "OK", "result" => []])); } $data = $database->select('groups', ['groupid (id)', 'groupname (name)'], ['groupname[~]' => $VARS['search'], "LIMIT" => 10]); @@ -333,7 +333,7 @@ switch ($VARS['action']) { break; case "checkpin": $pin = ""; - if (is_empty($VARS['pin'])) { + if (empty($VARS['pin'])) { http_response_code(400); die("\"400 Bad Request\""); } diff --git a/app.php b/app.php index f53c5d7..55a8421 100644 --- a/app.php +++ b/app.php @@ -14,7 +14,7 @@ if ($_SESSION['loggedin'] != true) { require_once __DIR__ . "/pages.php"; $pageid = "home"; -if (isset($_GET['page']) && !is_empty($_GET['page'])) { +if (isset($_GET['page']) && !empty($_GET['page'])) { $pg = strtolower($_GET['page']); $pg = preg_replace('/[^0-9a-z_]/', "", $pg); if (array_key_exists($pg, PAGES) && file_exists(__DIR__ . "/pages/" . $pg . ".php")) { @@ -66,9 +66,9 @@ header("Link: ; rel=preload; as=script", fals get(MESSAGES[$_GET['msg']]['string'], false); } else { $alertmsg = $Strings->build(MESSAGES[$_GET['msg']]['string'], ["arg" => strip_tags($_GET['arg'])], false); diff --git a/index.php b/index.php index e5d4003..d1fceae 100644 --- a/index.php +++ b/index.php @@ -50,7 +50,7 @@ if (empty($VARS['progress'])) { $username_ok = true; break; default: - if (!is_empty($error)) { + if (!empty($error)) { $alert = $error; } else { $alert = $Strings->get("login error", false); @@ -99,7 +99,7 @@ if (empty($VARS['progress'])) { } } else if ($VARS['progress'] == "chpasswd") { engageRateLimit(); - if (!is_empty($_SESSION['username'])) { + if (!empty($_SESSION['username'])) { $user = User::byUsername($_SESSION['username']); try { diff --git a/lib/IPUtils.lib.php b/lib/IPUtils.lib.php index fe70f21..99a2819 100644 --- a/lib/IPUtils.lib.php +++ b/lib/IPUtils.lib.php @@ -77,7 +77,7 @@ class IPUtils { ]; $valid = false; foreach ($cloudflare_ips_v6 as $cidr) { - if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { + if ($this::ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { $valid = true; break; } @@ -102,7 +102,7 @@ class IPUtils { ]; $valid = false; foreach ($cloudflare_ips_v4 as $cidr) { - if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { + if ($this::ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { $valid = true; break; } @@ -120,7 +120,7 @@ class IPUtils { // If CloudFlare is in the mix, we should use it. // Check if the request is actually from CloudFlare before trusting it. if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { - if (validateCloudflare()) { + if ($this::validateCloudflare()) { return $_SERVER["HTTP_CF_CONNECTING_IP"]; } } diff --git a/lib/Log.lib.php b/lib/Log.lib.php index 687a3af..15d8bb3 100644 --- a/lib/Log.lib.php +++ b/lib/Log.lib.php @@ -18,7 +18,7 @@ class Log { public static function insert($type, $user, string $data = "") { global $database; // find IP address - $ip = getClientIP(); + $ip = IPUtils::getClientIP(); if (gettype($type) == "object" && is_a($type, "LogType")) { $type = $type->getType(); } diff --git a/lib/User.lib.php b/lib/User.lib.php index 7ada9af..0949b1d 100644 --- a/lib/User.lib.php +++ b/lib/User.lib.php @@ -63,7 +63,7 @@ class User { global $database; $database->insert('accounts', [ 'username' => strtolower($username), - 'password' => (is_null($password) ? null : encryptPassword($password)), + 'password' => (is_null($password) ? null : password_hash($password, PASSWORD_BCRYPT)), 'realname' => $realname, 'email' => $email, 'phone1' => $phone1, @@ -215,10 +215,10 @@ class User { } function sendAlertEmail(string $appname = SITE_TITLE) { - if (is_empty(ADMIN_EMAIL) || filter_var(ADMIN_EMAIL, FILTER_VALIDATE_EMAIL) === FALSE) { + if (empty(ADMIN_EMAIL) || filter_var(ADMIN_EMAIL, FILTER_VALIDATE_EMAIL) === FALSE) { return "invalid_to_email"; } - if (is_empty(FROM_EMAIL) || filter_var(FROM_EMAIL, FILTER_VALIDATE_EMAIL) === FALSE) { + if (empty(FROM_EMAIL) || filter_var(FROM_EMAIL, FILTER_VALIDATE_EMAIL) === FALSE) { return "invalid_from_email"; } @@ -251,7 +251,7 @@ class User { $mail->addAddress(ADMIN_EMAIL, "System Admin"); $mail->isHTML(false); $mail->Subject = $Strings->get("admin alert email subject", false); - $mail->Body = $Strings->build("admin alert email message", ["username" => $this->username, "datetime" => date("Y-m-d H:i:s"), "ipaddr" => getClientIP(), "appname" => $appname], false); + $mail->Body = $Strings->build("admin alert email message", ["username" => $this->username, "datetime" => date("Y-m-d H:i:s"), "ipaddr" => IPUtils::getClientIP(), "appname" => $appname], false); if (!$mail->send()) { return $mail->ErrorInfo; diff --git a/mobile/index.php b/mobile/index.php index c05830c..6985e68 100644 --- a/mobile/index.php +++ b/mobile/index.php @@ -23,7 +23,7 @@ if (MOBILE_ENABLED !== TRUE) { } // Make sure we have a username and access key -if (is_empty($VARS['username']) || is_empty($VARS['key'])) { +if (empty($VARS['username']) || empty($VARS['key'])) { http_response_code(401); die(json_encode(["status" => "ERROR", "msg" => "Missing username and/or access key."])); } diff --git a/required.php b/required.php index 028de64..7a168d6 100644 --- a/required.php +++ b/required.php @@ -133,42 +133,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { define("GET", true); } -/** - * Checks if a string or whatever is empty. - * @param $str The thingy to check - * @return boolean True if it's empty or whatever. - */ -function is_empty($str) { - return (is_null($str) || !isset($str) || $str == ''); -} - -/** - * Checks if an email address is valid. - * @param string $email Email to check - * @return boolean True if email passes validation, else false. - */ -function isValidEmail($email) { - return filter_var($email, FILTER_VALIDATE_EMAIL); -} - -/** - * Hashes the given plaintext password - * @param String $password - * @return String the hash, using bcrypt - */ -function encryptPassword($password) { - return password_hash($password, PASSWORD_BCRYPT); -} - -/** - * Securely verify a password and its hash - * @param String $password - * @param String $hash the hash to compare to - * @return boolean True if password OK, else false - */ -function comparePassword($password, $hash) { - return password_verify($password, $hash); -} function dieifnotloggedin() { if ($_SESSION['loggedin'] != true) { @@ -193,44 +157,6 @@ function checkDBError($specials = []) { } } -/* - * http://stackoverflow.com/a/20075147 - */ -if (!function_exists('base_url')) { - - function base_url($atRoot = FALSE, $atCore = FALSE, $parse = FALSE) { - if (isset($_SERVER['HTTP_HOST'])) { - $http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http'; - $hostname = $_SERVER['HTTP_HOST']; - $dir = str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']); - - $core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY); - $core = $core[0]; - - $tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s"); - $end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir); - $base_url = sprintf($tmplt, $http, $hostname, $end); - } else - $base_url = 'http://localhost/'; - - if ($parse) { - $base_url = parse_url($base_url); - if (isset($base_url['path'])) - if ($base_url['path'] == '/') - $base_url['path'] = ''; - } - - return $base_url; - } - -} - -function redirectToPageId($id, $args, $dontdie) { - header('Location: ' . URL . '?id=' . $id . $args); - if (is_null($dontdie)) { - die("Please go to " . URL . '?id=' . $id . $args); - } -} function redirectIfNotLoggedIn() { if ($_SESSION['loggedin'] !== TRUE) { @@ -239,132 +165,6 @@ function redirectIfNotLoggedIn() { } } -/** - * Check if a given ipv4 address is in a given cidr - * @param string $ip IP to check in IPV4 format eg. 127.0.0.1 - * @param string $range IP/CIDR netmask eg. 127.0.0.0/24, also 127.0.0.1 is accepted and /32 assumed - * @return boolean true if the ip is in this range / false if not. - * @author Thorsten Ott - */ -function ip4_in_cidr($ip, $cidr) { - if (strpos($cidr, '/') == false) { - $cidr .= '/32'; - } - // $range is in IP/CIDR format eg 127.0.0.1/24 - list( $cidr, $netmask ) = explode('/', $cidr, 2); - $range_decimal = ip2long($cidr); - $ip_decimal = ip2long($ip); - $wildcard_decimal = pow(2, ( 32 - $netmask)) - 1; - $netmask_decimal = ~ $wildcard_decimal; - return ( ( $ip_decimal & $netmask_decimal ) == ( $range_decimal & $netmask_decimal ) ); -} - -/** - * Check if a given ipv6 address is in a given cidr - * @param string $ip IP to check in IPV6 format - * @param string $cidr CIDR netmask - * @return boolean true if the IP is in this range, false otherwise. - * @author MW. - */ -function ip6_in_cidr($ip, $cidr) { - $address = inet_pton($ip); - $subnetAddress = inet_pton(explode("/", $cidr)[0]); - $subnetMask = explode("/", $cidr)[1]; - - $addr = str_repeat("f", $subnetMask / 4); - switch ($subnetMask % 4) { - case 0: - break; - case 1: - $addr .= "8"; - break; - case 2: - $addr .= "c"; - break; - case 3: - $addr .= "e"; - break; - } - $addr = str_pad($addr, 32, '0'); - $addr = pack("H*", $addr); - - $binMask = $addr; - return ($address & $binMask) == $subnetAddress; -} - -/** - * Check if the REMOTE_ADDR is on Cloudflare's network. - * @return boolean true if it is, otherwise false - */ -function validateCloudflare() { - if (filter_var($_SERVER["REMOTE_ADDR"], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { - // Using IPv6 - $cloudflare_ips_v6 = [ - "2400:cb00::/32", - "2405:8100::/32", - "2405:b500::/32", - "2606:4700::/32", - "2803:f800::/32", - "2c0f:f248::/32", - "2a06:98c0::/29" - ]; - $valid = false; - foreach ($cloudflare_ips_v6 as $cidr) { - if (ip6_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { - $valid = true; - break; - } - } - } else { - // Using IPv4 - $cloudflare_ips_v4 = [ - "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", - "131.0.72.0/22", - "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" - ]; - $valid = false; - foreach ($cloudflare_ips_v4 as $cidr) { - if (ip4_in_cidr($_SERVER["REMOTE_ADDR"], $cidr)) { - $valid = true; - break; - } - } - } - return $valid; -} - -/** - * Makes a good guess at the client's real IP address. - * - * @return string Client IP or `0.0.0.0` if we can't find anything - */ -function getClientIP() { - // If CloudFlare is in the mix, we should use it. - // Check if the request is actually from CloudFlare before trusting it. - if (isset($_SERVER["HTTP_CF_CONNECTING_IP"])) { - if (validateCloudflare()) { - return $_SERVER["HTTP_CF_CONNECTING_IP"]; - } - } - - if (isset($_SERVER["REMOTE_ADDR"])) { - return $_SERVER["REMOTE_ADDR"]; - } - - return "0.0.0.0"; // This will not happen unless we aren't a web server -} - /** * Check if the client's IP has been doing too many brute-force-friendly * requests lately. @@ -378,12 +178,12 @@ function engageRateLimit() { global $database; $delay = date("Y-m-d H:i:s", strtotime("-2 seconds")); $database->delete('rate_limit', ["lastaction[<]" => $delay]); - if ($database->has('rate_limit', ["AND" => ["ipaddr" => getClientIP()]])) { + if ($database->has('rate_limit', ["AND" => ["ipaddr" => IPUtils::getClientIP()]])) { http_response_code(429); // JSONify it so API clients don't scream too loud die(json_encode(["status" => "ERROR", "msg" => "You're going too fast. Slow down, mkay?"])); } else { // Add a record for the IP address - $database->insert('rate_limit', ["ipaddr" => getClientIP(), "lastaction" => date("Y-m-d H:i:s")]); + $database->insert('rate_limit', ["ipaddr" => IPUtils::getClientIP(), "lastaction" => date("Y-m-d H:i:s")]); } } \ No newline at end of file diff --git a/setup.php b/setup.php index 7b7381f..42633df 100644 --- a/setup.php +++ b/setup.php @@ -14,7 +14,7 @@ if ($database->has('accounts', ["[>]assigned_permissions" => ["uid" => "uid"]], die("An admin account already exists, exiting."); } -if (is_empty($_POST['username']) || is_empty($_POST['password']) || is_empty($_POST['realname'])) { +if (empty($_POST['username']) || empty($_POST['password']) || empty($_POST['realname'])) { ?> Admin Account Creation