diff --git a/inc/SP/Api/ApiUtil.class.php b/inc/SP/Api/ApiUtil.class.php index f27d4faa..9574fec1 100644 --- a/inc/SP/Api/ApiUtil.class.php +++ b/inc/SP/Api/ApiUtil.class.php @@ -29,6 +29,7 @@ defined('APP_ROOT') || die(); use SP\Core\Exceptions\SPException; use SP\DataModel\TrackData; use SP\Mgmt\Tracks\Track; +use SP\Util\HttpUtil; use SP\Util\Util; /** @@ -48,7 +49,7 @@ class ApiUtil try { $TrackData = new TrackData(); $TrackData->setTrackSource('API'); - $TrackData->setTrackIp(Util::getClientAddress()); + $TrackData->setTrackIp(HttpUtil::getClientAddress()); Track::getItem($TrackData)->add(); } catch (SPException $e) { diff --git a/inc/SP/Controller/LoginController.class.php b/inc/SP/Controller/LoginController.class.php index 2b8756e9..c010f9ed 100644 --- a/inc/SP/Controller/LoginController.class.php +++ b/inc/SP/Controller/LoginController.class.php @@ -59,6 +59,7 @@ use SP\Mgmt\Users\UserPassRecover; use SP\Mgmt\Users\UserPreferences; use SP\Mgmt\Users\UserUtil; use SP\Util\Checks; +use SP\Util\HttpUtil; use SP\Util\Json; use SP\Util\Util; @@ -191,7 +192,7 @@ class LoginController try { $TrackData = new TrackData(); $TrackData->setTrackSource('Login'); - $TrackData->setTrackIp(Util::getClientAddress()); + $TrackData->setTrackIp(HttpUtil::getClientAddress()); $attempts = count(Track::getItem($TrackData)->getTracksForClientFromTime(time() - self::TIME_TRACKING)); } catch (SPException $e) { @@ -222,7 +223,7 @@ class LoginController try { $TrackData = new TrackData(); $TrackData->setTrackSource('Login'); - $TrackData->setTrackIp(Util::getClientAddress()); + $TrackData->setTrackIp(HttpUtil::getClientAddress()); Track::getItem($TrackData)->add(); } catch (SPException $e) { diff --git a/inc/SP/Controller/MainController.class.php b/inc/SP/Controller/MainController.class.php index 086104b2..58fb20a3 100644 --- a/inc/SP/Controller/MainController.class.php +++ b/inc/SP/Controller/MainController.class.php @@ -54,6 +54,7 @@ use SP\Mgmt\Notices\Notice; use SP\Mgmt\PublicLinks\PublicLink; use SP\Mgmt\Users\User; use SP\Util\Checks; +use SP\Util\HttpUtil; use SP\Util\Util; /** @@ -606,7 +607,7 @@ class MainController extends ControllerBase implements ActionsInterface $Message = new NoticeMessage(); $Message->setTitle(__('Enlace visualizado')); $Message->addDescription(sprintf('%s : %s', __('Cuenta'), $PublicLink->getItemId())); - $Message->addDescription(sprintf('%s : %s', __('Origen'), Checks::demoIsEnabled() ? '*.*.*.*' : Util::getClientAddress(true))); + $Message->addDescription(sprintf('%s : %s', __('Origen'), Checks::demoIsEnabled() ? '*.*.*.*' : HttpUtil::getClientAddress(true))); $Message->addDescription(sprintf('%s : %s', __('Agente'), Request::getRequestHeaders('HTTP_USER_AGENT'))); $Message->addDescription(sprintf('HTTPS : %s', Checks::httpsEnabled() ? 'ON' : 'OFF')); diff --git a/inc/SP/Core/Crypt/SecureKeyCookie.class.php b/inc/SP/Core/Crypt/SecureKeyCookie.class.php index e25e549e..4677d841 100644 --- a/inc/SP/Core/Crypt/SecureKeyCookie.class.php +++ b/inc/SP/Core/Crypt/SecureKeyCookie.class.php @@ -28,6 +28,7 @@ use Defuse\Crypto\Exception\CryptoException; use Defuse\Crypto\Key; use SP\Core\Init; use SP\Http\Request; +use SP\Util\HttpUtil; use SP\Util\Util; /** @@ -99,7 +100,7 @@ class SecureKeyCookie extends Cookie */ public function getCypher() { - return md5(Request::getRequestHeaders('User-Agent') . Util::getClientAddress()); + return md5(Request::getRequestHeaders('User-Agent') . HttpUtil::getClientAddress()); } /** diff --git a/inc/SP/Log/Email.class.php b/inc/SP/Log/Email.class.php index 2982b490..1f681ace 100644 --- a/inc/SP/Log/Email.class.php +++ b/inc/SP/Log/Email.class.php @@ -33,6 +33,7 @@ use SP\Core\Messages\NoticeMessage; use SP\Core\Session; use SP\Html\Html; use SP\Util\Checks; +use SP\Util\HttpUtil; use SP\Util\Util; /** @@ -61,7 +62,7 @@ class Email if ($isEvent === true) { $performer = Session::getUserData()->getUserLogin() ?: __('N/D'); $body[] = sprintf('%s: %s', Html::strongText(__('Acción')), $LogMessage->getAction(true)); - $body[] = sprintf('%s: %s (%s)', Html::strongText(__('Realizado por')), $performer, Util::getClientAddress(true)); + $body[] = sprintf('%s: %s (%s)', Html::strongText(__('Realizado por')), $performer, HttpUtil::getClientAddress(true)); $Mail->addCC(Config::getConfig()->getMailFrom()); } diff --git a/inc/SP/Log/Log.class.php b/inc/SP/Log/Log.class.php index c22c89ee..7f0c5f7a 100644 --- a/inc/SP/Log/Log.class.php +++ b/inc/SP/Log/Log.class.php @@ -32,6 +32,7 @@ use SP\Core\Session; use SP\Storage\DB; use SP\Storage\QueryData; use SP\Util\Checks; +use SP\Util\HttpUtil; use SP\Util\Util; defined('APP_ROOT') || die(); @@ -178,7 +179,7 @@ class Log extends ActionLog $Data->setQuery($query); $Data->addParam(Session::getUserData()->getUserLogin()); $Data->addParam(Session::getUserData()->getUserId()); - $Data->addParam(Util::getClientAddress(true)); + $Data->addParam(HttpUtil::getClientAddress(true)); $Data->addParam(utf8_encode($this->LogMessage->getAction(true))); $Data->addParam($this->getLogLevel()); $Data->addParam(utf8_encode($description)); @@ -217,7 +218,7 @@ class Log extends ActionLog $msg .= $this->LogMessage->getAction(true) . '|'; $msg .= $description . '|'; $msg .= '0|'; - $msg .= sprintf('ip_addr="%s" user_name="%s"', Util::getClientAddress(), Session::getUserData()->getUserLogin()); + $msg .= sprintf('ip_addr="%s" user_name="%s"', HttpUtil::getClientAddress(), Session::getUserData()->getUserLogin()); $Syslog = new Syslog(); $Syslog->setIsRemote(Checks::remoteSyslogIsEnabled()); diff --git a/inc/SP/Mgmt/PublicLinks/PublicLink.class.php b/inc/SP/Mgmt/PublicLinks/PublicLink.class.php index 338afcf6..e1dbb354 100644 --- a/inc/SP/Mgmt/PublicLinks/PublicLink.class.php +++ b/inc/SP/Mgmt/PublicLinks/PublicLink.class.php @@ -38,6 +38,7 @@ use SP\Mgmt\ItemTrait; use SP\Mgmt\Users\UserUtil; use SP\Storage\DB; use SP\Storage\QueryData; +use SP\Util\HttpUtil; use SP\Util\Util; defined('APP_ROOT') || die(); @@ -67,7 +68,7 @@ class PublicLink extends PublicLinkBase implements ItemInterface public function addLinkView() { $this->itemData->addCountViews(); - $this->updateUseInfo(Util::getClientAddress(true)); + $this->updateUseInfo(HttpUtil::getClientAddress(true)); $Log = new Log(); $LogMessage = $Log->getLogMessage(); diff --git a/inc/SP/Util/HttpUtil.class.php b/inc/SP/Util/HttpUtil.class.php index ba194786..76a01cb0 100644 --- a/inc/SP/Util/HttpUtil.class.php +++ b/inc/SP/Util/HttpUtil.class.php @@ -24,6 +24,8 @@ namespace SP\Util; +use SP\Http\Request; + /** * Class HttpUtil * @@ -52,33 +54,18 @@ class HttpUtil */ public static function getHttpHost() { - // Check in style of RFC 7239 - if (isset($_SERVER['HTTP_FORWARDED']) - && preg_match('/proto=(\w+);/i', $_SERVER['HTTP_FORWARDED'], $matchesProto) - && preg_match('/host=(\w+);/i', $_SERVER['HTTP_FORWARDED'], $matchesHost) - ) { - // Removes possible `"`-chars - $protocol = strtolower($matchesProto[0]); - $host = strtolower($matchesHost[0]); + $forwarded = self::getForwardedData(); - // Check if prtocol and host are not empty - if (strlen($protocol) > 0 && strlen($host) > 0) { - return $protocol . '://' . $host; - } + // Check in style of RFC 7239 + if (null !== $forwarded) { + return strtolower($forwarded['proto'] . '://' . $forwarded['host']); } + $xForward = self::getXForwardedData(); + // Check (deprecated) de facto standard - if (isset($_SERVER['HTTP_X_FORWARDED_HOST'], $_SERVER['HTTP_X_FORWARDED_PROTO'])) { - // This only could be http or https - $protocol = str_replace('"', '', trim($_SERVER['HTTP_X_FORWARDED_PROTO'])); - - // This may be example.com or sub.example.com/syspass - $host = str_replace('"', '', trim($_SERVER['HTTP_X_FORWARDED_HOST'])); - - // Check if protocol and host are not empty - if (strlen($protocol) > 0 && strlen($host) > 0) { - return $protocol . '://' . $host; - } + if (null !== $xForward) { + return strtolower($xForward['proto'] . '://' . $xForward['host']); } // We got called directly @@ -88,4 +75,98 @@ class HttpUtil return 'http://' . $_SERVER['HTTP_HOST']; } + + /** + * Devolver datos de forward RFC 7239 + * + * @see https://tools.ietf.org/html/rfc7239#section-7.5 + * @return array|null + */ + public static function getForwardedData() + { + $forwarded = Request::getRequestHeaders('HTTP_FORWARDED'); + + // Check in style of RFC 7239 + if ($forwarded !== '' + && preg_match('/proto=(\w+);/i', $forwarded, $matchesProto) + && preg_match('/host=(\w+);/i', $forwarded, $matchesHost) + ) { + $data = [ + 'host ' => $matchesHost[0], + 'proto' => $matchesProto[0], + 'for' => self::getForwardedFor() + ]; + + // Check if protocol and host are not empty + if (!empty($data['proto']) && !empty($data['host'])) { + return $data; + } + } + + return null; + } + + /** + * Devolver la dirección IP del cliente a través de proxy o directo + * + * @return array|string + */ + public static function getForwardedFor() + { + if (preg_match_all('/for=([0-9\.]+)[,;]+/i', + Request::getRequestHeaders('HTTP_FORWARDED'), $matchesFor)) { + return $matchesFor[1]; + } + + if (preg_match_all('/([\w.:]+)(,|$)/', + Request::getRequestHeaders('HTTP_X_FORWARDED_FOR'), $matchesFor)) { + return $matchesFor[1]; + } + + return $_SERVER['REMOTE_ADDR']; + } + + /** + * Devolver datos de x-forward + * + * @return array|null + */ + public static function getXForwardedData() + { + $forwardedHost = Request::getRequestHeaders('HTTP_X_FORWARDED_HOST'); + $forwardedProto = Request::getRequestHeaders('HTTP_X_FORWARDED_PROTO'); + + // Check (deprecated) de facto standard + if (!empty($forwardedHost) && !empty($forwardedProto)) { + $data = [ + 'host' => trim(str_replace('"', '', $forwardedHost)), + 'proto' => trim(str_replace('"', '', $forwardedProto)), + 'for' => self::getForwardedFor() + ]; + + // Check if protocol and host are not empty + if (!empty($data['host']) && !empty($data['proto'])) { + return $data; + } + } + + return null; + } + + /** + * Devolver la dirección IP del cliente + * + * @param bool $fullForwarded Devolver la cadena de forward completa + * @return string|array + */ + public static function getClientAddress($fullForwarded = false) + { + $forwarded = self::getForwardedFor(); + + if (is_array($forwarded)) { + return $fullForwarded ? implode(',', $forwarded) : $forwarded[0]; + } + + return $forwarded; + } } \ No newline at end of file diff --git a/inc/SP/Util/Util.class.php b/inc/SP/Util/Util.class.php index 244e04ff..199d0fb9 100644 --- a/inc/SP/Util/Util.class.php +++ b/inc/SP/Util/Util.class.php @@ -386,7 +386,7 @@ class Util */ public static function getVersion($retBuild = false, $normalized = false) { - $build = 17091801; + $build = 17091802; $version = [2, 1, 15]; if ($normalized === true) { @@ -659,23 +659,4 @@ class Util return [0, 0]; } - - /** - * Devolver la dirección IP del cliente - * - * @param bool $fullForwarded Devolver la cadena de forward completa - * @return string - */ - public static function getClientAddress($fullForwarded = false) - { - $forwarded = Request::getRequestHeaders('X-Forwarded-For'); - - if ($forwarded !== '') { - if (preg_match_all('/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}/', $forwarded, $matches)) { - return $fullForwarded ? implode(',', $matches[0]) : $matches[0][0]; - } - } - - return $_SERVER['REMOTE_ADDR']; - } } diff --git a/inc/themes/material-blue/js/app-theme.min.js b/inc/themes/material-blue/js/app-theme.min.js index d7582b07..986aac77 100644 --- a/inc/themes/material-blue/js/app-theme.min.js +++ b/inc/themes/material-blue/js/app-theme.min.js @@ -1,5 +1,5 @@ var $jscomp={scope:{},findInternal:function(a,e,c){a instanceof String&&(a=String(a));for(var g=a.length,k=0;k"); a.passwordData.complexity.numbers&&(d+="1234567890");a.passwordData.complexity.chars&&(d+="abcdefghijklmnopqrstuvwxyz",a.passwordData.complexity.uppercase&&(d+="ABCDEFGHIJKLMNOPQRSTUVWXYZ"));for(;f++