diff --git a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Http.php b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Http.php index d80d6705a..4d7bbc3c9 100644 --- a/snappymail/v/0.0.0/app/libraries/MailSo/Base/Http.php +++ b/snappymail/v/0.0.0/app/libraries/MailSo/Base/Http.php @@ -175,251 +175,6 @@ class Http return $sIp; } - public function SendPostRequest(string $sUrl, array $aPost = array(), string $sCustomUserAgent = 'MailSo Http User Agent (v1)', int &$iCode = 0, - ?\MailSo\Log\Logger $oLogger = null, int $iTimeout = 20, string $sProxy = '', string $sProxyAuth = '') : string - { - $aOptions = array( - CURLOPT_URL => $sUrl, - CURLOPT_HEADER => false, - CURLOPT_FAILONERROR => true, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => \http_build_query($aPost, '', '&'), - CURLOPT_TIMEOUT => (int) $iTimeout - ); - - if (\strlen($sCustomUserAgent)) - { - $aOptions[CURLOPT_USERAGENT] = $sCustomUserAgent; - } - - if (\strlen($sProxy)) - { - $aOptions[CURLOPT_PROXY] = $sProxy; - if (\strlen($sProxyAuth)) - { - $aOptions[CURLOPT_PROXYUSERPWD] = $sProxyAuth; - } - } - - $oCurl = \curl_init(); - \curl_setopt_array($oCurl, $aOptions); - - if ($oLogger) - { - $oLogger->Write('cURL: Send post request: '.$sUrl); - } - - $mResult = \curl_exec($oCurl); - - $iCode = (int) \curl_getinfo($oCurl, CURLINFO_HTTP_CODE); - $sContentType = (string) \curl_getinfo($oCurl, CURLINFO_CONTENT_TYPE); - - if ($oLogger) - { - $oLogger->Write('cURL: Post request result: (Status: '.$iCode.', ContentType: '.$sContentType.')'); - if (false === $mResult || 200 !== $iCode) - { - $oLogger->Write('cURL: Error: '.\curl_error($oCurl), \MailSo\Log\Enumerations\Type::WARNING); - } - } - - if (\is_resource($oCurl)) - { - \curl_close($oCurl); - } - - return $mResult; - } - - static public function DetectAndHackFollowLocationUrl(string $sUrl, array &$aOptions, ?\MailSo\Log\Logger $oLogger = null) : string - { - $sNewUrl = null; - $sUrl = isset($aOptions[CURLOPT_URL]) ? $aOptions[CURLOPT_URL] : $sUrl; - - if (isset($aOptions[CURLOPT_FOLLOWLOCATION]) && $aOptions[CURLOPT_FOLLOWLOCATION] && \strlen($sUrl) && - \ini_get('open_basedir') !== '') - { - $aOptions[CURLOPT_FOLLOWLOCATION] = false; - - $iMaxRedirects = isset($aOptions[CURLOPT_MAXREDIRS]) ? $aOptions[CURLOPT_MAXREDIRS] : 5; - $iRedirectLimit = $iMaxRedirects; - - if ($iRedirectLimit > 0) - { - $sNewUrl = $sUrl; - - $oCurl = \curl_init($sUrl); - - $aAddOptions = array( - CURLOPT_URL => $sUrl, - CURLOPT_HEADER => true, - CURLOPT_NOBODY => true, - CURLOPT_FAILONERROR => false, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_FOLLOWLOCATION => false, - CURLOPT_FORBID_REUSE => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_TIMEOUT => 5 - ); - - if (isset($aOptions[CURLOPT_HTTPHEADER]) && \is_array($aOptions[CURLOPT_HTTPHEADER]) && \count($aOptions[CURLOPT_HTTPHEADER])) - { - $aAddOptions[CURLOPT_HTTPHEADER] = $aOptions[CURLOPT_HTTPHEADER]; - } - - \curl_setopt_array($oCurl, $aAddOptions); - - do - { - \curl_setopt($oCurl, CURLOPT_URL, $sNewUrl); - - $sHeader = \curl_exec($oCurl); - if (\curl_errno($oCurl)) - { - $iCode = 0; - } - else - { - $iCode = \curl_getinfo($oCurl, CURLINFO_HTTP_CODE); - if ($iCode === 301 || $iCode === 302) - { - $aMatches = array(); - \preg_match('/Location:(.*?)\n/', $sHeader, $aMatches); - $sNewUrl = \trim(\array_pop($aMatches)); - - if ($oLogger) - { - $oLogger->Write('cUrl: Location URL: '.$sNewUrl); - } - } - else - { - $iCode = 0; - } - } - - } while ($iCode && --$iRedirectLimit); - - \curl_close($oCurl); - if ($iRedirectLimit > 0 && \strlen($sNewUrl)) - { - $aOptions[CURLOPT_URL] = $sNewUrl; - } - } - } - - return null === $sNewUrl ? $sUrl : $sNewUrl; - } - - /** - * @param resource $rFile - */ - public function SaveUrlToFile(string $sUrl, $rFile, string $sCustomUserAgent = 'MailSo Http User Agent (v1)', string &$sContentType = '', int &$iCode = 0, - ?\MailSo\Log\Logger $oLogger = null, int $iTimeout = 10, string $sProxy = '', string $sProxyAuth = '', array $aHttpHeaders = array(), bool $bFollowLocation = true) : bool - { - if (null === $sCustomUserAgent) - { - $sCustomUserAgent = 'MailSo Http User Agent (v1)'; - } - - if (!is_resource($rFile)) - { - if ($oLogger) - { - $oLogger->Write('cURL: input resource invalid.', \MailSo\Log\Enumerations\Type::WARNING); - } - - return false; - } - - $sUrl = \trim($sUrl); - if ('//' === substr($sUrl, 0, 2)) - { - $sUrl = 'http:'.$sUrl; - } - - $aOptions = array( - CURLOPT_URL => $sUrl, - CURLOPT_HEADER => false, - CURLOPT_FAILONERROR => true, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FOLLOWLOCATION => $bFollowLocation, - CURLOPT_MAXREDIRS => 7, - CURLOPT_FILE => $rFile, - CURLOPT_TIMEOUT => (int) $iTimeout - ); - - if (\strlen($sCustomUserAgent)) - { - $aOptions[CURLOPT_USERAGENT] = $sCustomUserAgent; - } - - if (\strlen($sProxy)) - { - $aOptions[CURLOPT_PROXY] = $sProxy; - if (\strlen($sProxyAuth)) - { - $aOptions[CURLOPT_PROXYUSERPWD] = $sProxyAuth; - } - } - - if (\count($aHttpHeaders)) - { - $aOptions[CURLOPT_HTTPHEADER] = $aHttpHeaders; - } - - if ($oLogger) - { - $oLogger->Write('cUrl: URL: '.$sUrl); -// if (isset($aOptions[CURLOPT_HTTPHEADER]) && \is_array($aOptions[CURLOPT_HTTPHEADER]) && \count($aOptions[CURLOPT_HTTPHEADER])) -// { -// $oLogger->Write('cUrl: Headers: '.\print_r($aOptions[CURLOPT_HTTPHEADER], true)); -// } - } - - static::DetectAndHackFollowLocationUrl($sUrl, $aOptions, $oLogger); - - $oCurl = \curl_init(); - \curl_setopt_array($oCurl, $aOptions); - - $bResult = \curl_exec($oCurl); - - $iCode = (int) \curl_getinfo($oCurl, CURLINFO_HTTP_CODE); - $sContentType = (string) \curl_getinfo($oCurl, CURLINFO_CONTENT_TYPE); - - if ($oLogger) - { - $oLogger->Write('cUrl: Request result: '.($bResult ? 'true' : 'false').' (Status: '.$iCode.', ContentType: '.$sContentType.')'); - if (!$bResult || 200 !== $iCode) - { - $oLogger->Write('cUrl: Error: '.\curl_error($oCurl), \MailSo\Log\Enumerations\Type::WARNING); - } - } - - if (\is_resource($oCurl)) - { - \curl_close($oCurl); - } - - return $bResult; - } - - public function GetUrlAsString(string $sUrl, string $sCustomUserAgent = 'MailSo Http User Agent (v1)', string &$sContentType = '', int &$iCode = 0, - ?\MailSo\Log\Logger $oLogger = null, int $iTimeout = 10, string $sProxy = '', string $sProxyAuth = '', array $aHttpHeaders = array(), bool $bFollowLocation = true) : string - { - $rMemFile = \MailSo\Base\ResourceRegistry::CreateMemoryResource(); - if ($this->SaveUrlToFile($sUrl, $rMemFile, $sCustomUserAgent, $sContentType, $iCode, $oLogger, $iTimeout, $sProxy, $sProxyAuth, $aHttpHeaders, $bFollowLocation) && \is_resource($rMemFile)) - { - \rewind($rMemFile); - return \stream_get_contents($rMemFile); - } - - return false; - } - public function ServerNotModifiedCache(int $iExpireTime, bool $bSetCacheHeader = true, string $sEtag = '') : bool { $bResult = false; diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php b/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php index 55c218cc2..a2e4021b7 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/ServiceActions.php @@ -334,7 +334,6 @@ class ServiceActions public function ServiceProxyExternal() : string { - $bResult = false; $sData = empty($this->aPaths[1]) ? '' : $this->aPaths[1]; if (!empty($sData) && $this->Config()->Get('labs', 'use_local_proxy_for_external_images', false)) { @@ -350,30 +349,25 @@ class ServiceActions if (\is_array($aData) && !empty($aData['Token']) && !empty($aData['Url']) && $aData['Token'] === Utils::GetConnectionToken()) { \header('X-Content-Location: '.$aData['Url']); - $iCode = 404; - $sContentType = ''; - $mResult = $this->oHttp->GetUrlAsString($aData['Url'], 'SnappyMail External Proxy', $sContentType, $iCode); - - if (false !== $mResult && 200 === $iCode && - \in_array($sContentType, array('image/png', 'image/jpeg', 'image/jpg', 'image/bmp', 'image/gif'))) - { - $bResult = true; - + $tmp = \tmpfile(); + $HTTP = \SnappyMail\HTTP\Request::factory(); + $HTTP->streamBodyTo($tmp); + $oResponse = $HTTP->doRequest('GET', $aData['Url']); + if ($oResponse && 200 === $oResponse->status + && \str_starts_with($oResponse->getHeader('content-type'), 'image/') + ) { $this->oActions->cacheByKey($sData); - \header('Content-Type: '.$sContentType); \header('Cache-Control: public'); \header('Expires: '.\gmdate('D, j M Y H:i:s', 2592000 + \time()).' UTC'); - echo $mResult; + \rewind($tmp); + \fpassthru($tmp); + exit; } } } - if (!$bResult) - { - \MailSo\Base\Http::StatusHeader(404); - } - + \MailSo\Base\Http::StatusHeader(404); return ''; } diff --git a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php index 31e4029c4..e8632de31 100644 --- a/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php +++ b/snappymail/v/0.0.0/app/libraries/RainLoop/Utils.php @@ -215,6 +215,23 @@ class Utils // return @\parse_ini_string(\file_get_contents($sFileName), $bProcessSections) ?: array(); } + public static function inOpenBasedir(string $name) : string + { + static $open_basedir; + if (null === $open_basedir) { + $open_basedir = \array_filter(\explode(PATH_SEPARATOR, \ini_get('open_basedir'))); + } + if ($open_basedir) { + foreach ($open_basedir as $dir) { + if (\str_starts_with($name, $dir)) { + return true; + } + } + return false; + } + return true; + } + /** * Replace control characters, ampersand, spaces and reserved characters (based on Win95 VFAT) * en.wikipedia.org/wiki/Filename#Reserved_characters_and_words diff --git a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php index 546bfe74c..9eeedcf50 100644 --- a/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php +++ b/snappymail/v/0.0.0/app/libraries/snappymail/pgp/gpg.php @@ -1385,25 +1385,13 @@ class GPG if ($binary && \is_executable($binary)) { return $binary; } - $locations = [ + $locations = \array_filter([ '/sw/bin/', '/usr/bin/', '/usr/local/bin/', '/opt/local/bin/', '/run/current-system/sw/bin/' - ]; - $open_basedir = \ini_get('open_basedir'); - if ($open_basedir) { - $open_basedir = \explode(PATH_SEPARATOR, $open_basedir); - $locations = \array_filter($locations, function($path) use ($open_basedir) { - foreach ($open_basedir as $dir) { - if (\str_starts_with($path, $open_basedir)) { - return true; - } - } - return false; - }); - } + ], '\RainLoop\Utils::inOpenBasedir'); foreach ($locations as $location) { if (\is_executable($location . $name)) { return $location . $name;